/*
* 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.ia32;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.VM_TypeReference;
import org.jikesrvm.compilers.opt.OPT_BURS;
import org.jikesrvm.compilers.opt.OPT_BURS_MemOp_Helpers;
import org.jikesrvm.compilers.opt.OPT_DefUse;
import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException;
import org.jikesrvm.compilers.opt.ir.Binary;
import org.jikesrvm.compilers.opt.ir.CacheOp;
import org.jikesrvm.compilers.opt.ir.Call;
import org.jikesrvm.compilers.opt.ir.CondMove;
import org.jikesrvm.compilers.opt.ir.GuardedBinary;
import org.jikesrvm.compilers.opt.ir.IfCmp;
import org.jikesrvm.compilers.opt.ir.LowTableSwitch;
import org.jikesrvm.compilers.opt.ir.MIR_BinaryAcc;
import org.jikesrvm.compilers.opt.ir.MIR_Call;
import org.jikesrvm.compilers.opt.ir.MIR_Compare;
import org.jikesrvm.compilers.opt.ir.MIR_CompareExchange;
import org.jikesrvm.compilers.opt.ir.MIR_CompareExchange8B;
import org.jikesrvm.compilers.opt.ir.MIR_CondBranch;
import org.jikesrvm.compilers.opt.ir.MIR_CondMove;
import org.jikesrvm.compilers.opt.ir.MIR_ConvertDW2QW;
import org.jikesrvm.compilers.opt.ir.MIR_Divide;
import org.jikesrvm.compilers.opt.ir.MIR_Lea;
import org.jikesrvm.compilers.opt.ir.MIR_LowTableSwitch;
import org.jikesrvm.compilers.opt.ir.MIR_Move;
import org.jikesrvm.compilers.opt.ir.MIR_Multiply;
import org.jikesrvm.compilers.opt.ir.MIR_Nullary;
import org.jikesrvm.compilers.opt.ir.MIR_RDTSC;
import org.jikesrvm.compilers.opt.ir.MIR_Set;
import org.jikesrvm.compilers.opt.ir.MIR_TrapIf;
import org.jikesrvm.compilers.opt.ir.MIR_Unary;
import org.jikesrvm.compilers.opt.ir.MIR_UnaryAcc;
import org.jikesrvm.compilers.opt.ir.Move;
import org.jikesrvm.compilers.opt.ir.Nullary;
import org.jikesrvm.compilers.opt.ir.OPT_BranchOperand;
import org.jikesrvm.compilers.opt.ir.OPT_BranchProfileOperand;
import org.jikesrvm.compilers.opt.ir.OPT_ConditionOperand;
import org.jikesrvm.compilers.opt.ir.OPT_ConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_DoubleConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_FloatConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_InlinedOsrTypeInfoOperand;
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_LongConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_MemoryOperand;
import org.jikesrvm.compilers.opt.ir.OPT_MethodOperand;
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.CALL_SAVE_VOLATILE;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GUARD_MOVE;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_ADC;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_ADD;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_AND;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_CALL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_CDQ;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_CMOV;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_CMP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FCMOV;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FCOMI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FCOMIP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FILD;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FIST;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLD;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLD1;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLDL2E;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLDL2T;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLDLG2;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLDLN2;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLDPI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FLDZ;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FMOV;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FPREM;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_FSTP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_IDIV;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_IMUL2;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_JCC;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_LEA;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_LOCK_CMPXCHG;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_LOCK_CMPXCHG8B;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_MOV;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_MOVSD;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_MOVSS;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_MOVSX__B;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_MOVZX__B;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_MUL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_NEG;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_NOT;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_OR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_RCR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_RDTSC;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SAR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SBB;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SET__B;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SHL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SHR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SUB;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_SYSCALL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_TRAPIF;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IA32_XOR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.IR_PROLOGUE;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_USHR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.MIR_LOWTABLESWITCH;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperandEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_StackLocationOperand;
import org.jikesrvm.compilers.opt.ir.OPT_TrapCodeOperand;
import org.jikesrvm.compilers.opt.ir.OPT_TrueGuardOperand;
import org.jikesrvm.compilers.opt.ir.OsrPoint;
import org.jikesrvm.compilers.opt.ir.Prologue;
import org.jikesrvm.compilers.opt.ir.TrapIf;
import org.jikesrvm.compilers.opt.ir.Unary;
import org.jikesrvm.compilers.opt.ir.ia32.OPT_BURSManagedFPROperand;
import org.jikesrvm.compilers.opt.ir.ia32.OPT_IA32ConditionOperand;
import org.jikesrvm.runtime.VM_Entrypoints;
import org.jikesrvm.runtime.VM_Magic;
import org.jikesrvm.runtime.VM_Runtime;
import org.vmmagic.unboxed.Offset;
/**
* Contains IA32-specific helper functions for BURS.
*/
abstract class OPT_BURS_Helpers extends OPT_BURS_MemOp_Helpers {
/** Constant log10(2), supported as an x87 constant */
private static final double LG2 = Double
.parseDouble("0.3010299956639811952256464283594894482");
/** Constant ln(2), supported as an x87 constant */
private static final double LN2 = Double
.parseDouble("0.6931471805599453094286904741849753009");
/** Constant log2(e), supported as an x87 constant */
private static final double L2E = Double
.parseDouble("1.4426950408889634073876517827983434472");
/** Constant log2(10), supported as an x87 constant */
private static final double L2T = Double
.parseDouble("3.3219280948873623478083405569094566090");
/**
* When emitting certain rules this holds the condition code state to be
* consumed by a parent rule
*/
private OPT_ConditionOperand cc;
/** Constructor */
OPT_BURS_Helpers(OPT_BURS burs) {
super(burs);
}
/**
* Create the MIR instruction given by operator from the Binary LIR operands
* @param operator the MIR operator
* @param s the instruction being replaced
* @param result the destination register/memory
* @param val1 the first operand
* @param val2 the second operand
*/
protected void EMIT_Commutative(OPT_Operator operator, OPT_Instruction s, OPT_Operand result, OPT_Operand val1, OPT_Operand val2) {
if(VM.VerifyAssertions) VM._assert(result.isRegister() || result.isMemory());
// Swap operands to reduce chance of generating a move or to normalize
// constants into val2
if (val2.similar(result) || val1.isConstant()) {
OPT_Operand temp = val1;
val1 = val2;
val2 = temp;
}
// Do we need to move prior to the operator - result = val1
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), val1)));
}
EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
}
/**
* Create the MIR instruction given by operator from the Binary LIR operands
* @param operator the MIR operator
* @param s the instruction being replaced
* @param result the destination register/memory
* @param val1 the first operand
* @param val2 the second operand
*/
protected void EMIT_NonCommutative(OPT_Operator operator, OPT_Instruction s, OPT_Operand result, OPT_Operand val1, OPT_Operand val2) {
if(VM.VerifyAssertions) VM._assert(result.isRegister() || result.isMemory());
if (result.similar(val1)) {
// Straight forward case where instruction is already in accumulate form
EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
} else if (!result.similar(val2)) {
// Move first operand to result and perform operator on result, if
// possible redundant moves should be remove by register allocator
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), val1)));
EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
} else {
// Potential to clobber second operand during move to result. Use a
// temporary register to perform the operation and rely on register
// allocator to remove redundant moves
OPT_RegisterOperand temp = regpool.makeTemp(result);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1)));
EMIT(MIR_BinaryAcc.mutate(s, operator, temp.copyRO(), val2));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result, temp.copyRO())));
}
}
/**
* Create the MIR instruction given by operator from the Binary LIR operands
* @param operator the MIR operator
* @param s the instruction being replaced
* @param result the destination register/memory
* @param value the first operand
*/
protected void EMIT_Unary(OPT_Operator operator, OPT_Instruction s, OPT_Operand result, OPT_Operand value) {
if(VM.VerifyAssertions) VM._assert(result.isRegister() || result.isMemory());
// Do we need to move prior to the operator - result = val1
if (!result.similar(value)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), value)));
}
EMIT(MIR_UnaryAcc.mutate(s, operator, result));
}
/**
* Create the MIR LEA instruction performing a few simplifications if possible
* @param s the instruction being replaced
* @param result the destination register
* @param mo the memory operand
*/
protected void EMIT_Lea(OPT_Instruction s, OPT_RegisterOperand result, OPT_MemoryOperand mo) {
// A memory operand is: base + scaled index + displacement
if ((mo.index == null) && mo.disp.isZero()) {
if (VM.VerifyAssertions) VM._assert(mo.scale == 0 && mo.base != null);
// If there is no index or displacement emit a move
EMIT(MIR_Move.mutate(s, IA32_MOV, result, mo.base));
} else if ((mo.index == null) && result.similar(mo.base)) {
if (VM.VerifyAssertions) VM._assert(mo.scale == 0);
// If there is no index and we're redefining the same register, emit an add
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(mo.disp.toInt())));
} else {
// Lea is simplest form
EMIT(MIR_Lea.mutate(s, IA32_LEA, result, mo));
}
}
/**
* Convert the given comparison with a boolean (int) value into a condition
* suitable for the carry flag
* @param x the value 1 (true) or 0 (false)
* @param cond either equal or not equal
* @return lower or higher equal
*/
protected static OPT_ConditionOperand BIT_TEST(int x, OPT_ConditionOperand cond) {
if (VM.VerifyAssertions) VM._assert((x==0)||(x==1));
if (VM.VerifyAssertions) VM._assert(EQ_NE(cond));
if ((x == 1 && cond.isEQUAL())||
(x == 0 && cond.isNOT_EQUAL())) {
return OPT_ConditionOperand.LOWER();
} else {
return OPT_ConditionOperand.HIGHER_EQUAL();
}
}
/**
* Follow a chain of Move operations filtering back to a def
*
* @param use the place to start from
* @return the operand at the start of the chain
*/
protected static OPT_Operand follow(OPT_Operand use) {
if (!use.isRegister()) {
return use;
} else {
OPT_RegisterOperand rop = use.asRegister();
OPT_RegisterOperandEnumeration defs = OPT_DefUse.defs(rop.getRegister());
if (!defs.hasMoreElements()) {
return use;
} else {
OPT_Operand def = defs.next();
if (defs.hasMoreElements()) {
return def;
} else {
OPT_Instruction instr = def.instruction;
if (Move.conforms(instr)) {
return follow(Move.getVal(instr));
} else if (MIR_Move.conforms(instr)) {
return follow(MIR_Move.getValue(instr));
} else {
return def;
}
}
}
}
}
/**
* Remember a condition code in a child node
*
* @param c condition code to record
*/
protected final void pushCOND(OPT_ConditionOperand c) {
if (VM.VerifyAssertions) {
VM._assert(cc == null);
}
cc = c;
}
/**
* Acquire remembered condition code in parent
*
* @return condition code
*/
protected final OPT_ConditionOperand consumeCOND() {
OPT_ConditionOperand ans = cc;
if (VM.VerifyAssertions) {
VM._assert(cc != null);
}
cc = null;
return ans;
}
/**
* Can an IV be the scale in a LEA instruction?
*
* @param op operand to examine
* @param trueCost the cost if this can be part of an LEA
* @return trueCost or INFINITE
*/
protected final int LEA_SHIFT(OPT_Operand op, int trueCost) {
return LEA_SHIFT(op, trueCost, INFINITE);
}
/**
* Can an IV be the scale in a LEA instruction?
*
* @param op operand to examine
* @param trueCost the cost if this can be part of an LEA
* @param falseCost the cost if this can't be part of an LEA
* @return trueCost or falseCost
*/
protected final int LEA_SHIFT(OPT_Operand op, int trueCost, int falseCost) {
if (op.isIntConstant()) {
int val = IV(op);
if (val >= 0 && val <= 3) {
return trueCost;
}
}
return falseCost;
}
protected final byte LEA_SHIFT(OPT_Operand op) {
switch (IV(op)) {
case 0:
return B_S;
case 1:
return W_S;
case 2:
return DW_S;
case 3:
return QW_S;
default:
throw new OPT_OptimizingCompilerException("bad val for LEA shift " + op);
}
}
/**
* Is the given instruction's constant operand a x87 floating point constant
*
* @param s the instruction to examine
* @param trueCost the cost if this is a valid constant
* @return trueCost or INFINITE depending on the given constant
*/
protected final int is387_FPC(OPT_Instruction s, int trueCost) {
OPT_Operand val = Binary.getVal2(s);
if (val instanceof OPT_FloatConstantOperand) {
OPT_FloatConstantOperand fc = (OPT_FloatConstantOperand) val;
if (fc.value == 1.0f) {
return trueCost;
} else if (fc.value == 0.0f) {
return trueCost;
} else if (fc.value == (float) Math.PI) {
return trueCost;
} else if (fc.value == (float) LG2) {
return trueCost;
} else if (fc.value == (float) LN2) {
return trueCost;
} else if (fc.value == (float) L2E) {
return trueCost;
} else if (fc.value == (float) L2T) {
return trueCost;
}
} else {
OPT_DoubleConstantOperand dc = (OPT_DoubleConstantOperand) val;
if (dc.value == 1.0) {
return trueCost;
} else if (dc.value == 0.0) {
return trueCost;
} else if (dc.value == Math.PI) {
return trueCost;
} else if (dc.value == LG2) {
return trueCost;
} else if (dc.value == LN2) {
return trueCost;
} else if (dc.value == L2E) {
return trueCost;
} else if (dc.value == L2T) {
return trueCost;
}
}
return INFINITE;
}
protected final OPT_Operator get387_FPC(OPT_Instruction s) {
OPT_Operand val = Binary.getVal2(s);
if (val instanceof OPT_FloatConstantOperand) {
OPT_FloatConstantOperand fc = (OPT_FloatConstantOperand) val;
if (fc.value == 1.0f) {
return IA32_FLD1;
} else if (fc.value == 0.0f) {
return IA32_FLDZ;
} else if (fc.value == (float) Math.PI) {
return IA32_FLDPI;
} else if (fc.value == (float) LG2) {
return IA32_FLDLG2;
} else if (fc.value == (float) LN2) {
return IA32_FLDLN2;
} else if (fc.value == (float) L2E) {
return IA32_FLDL2E;
} else if (fc.value == (float) L2T) {
return IA32_FLDL2T;
}
} else {
OPT_DoubleConstantOperand dc = (OPT_DoubleConstantOperand) val;
if (dc.value == 1.0) {
return IA32_FLD1;
} else if (dc.value == 0.0) {
return IA32_FLDZ;
} else if (dc.value == Math.PI) {
return IA32_FLDPI;
} else if (dc.value == LG2) {
return IA32_FLDLG2;
} else if (dc.value == LN2) {
return IA32_FLDLN2;
} else if (dc.value == L2E) {
return IA32_FLDL2E;
} else if (dc.value == L2T) {
return IA32_FLDL2T;
}
}
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers", "unexpected 387 constant " + val);
}
protected final OPT_IA32ConditionOperand COND(OPT_ConditionOperand op) {
return new OPT_IA32ConditionOperand(op);
}
// Get particular physical registers
protected final OPT_Register getEAX() {
return getIR().regpool.getPhysicalRegisterSet().getEAX();
}
protected final OPT_Register getECX() {
return getIR().regpool.getPhysicalRegisterSet().getECX();
}
protected final OPT_Register getEDX() {
return getIR().regpool.getPhysicalRegisterSet().getEDX();
}
protected final OPT_Register getEBX() {
return getIR().regpool.getPhysicalRegisterSet().getEBX();
}
protected final OPT_Register getESP() {
return getIR().regpool.getPhysicalRegisterSet().getESP();
}
protected final OPT_Register getEBP() {
return getIR().regpool.getPhysicalRegisterSet().getEBP();
}
protected final OPT_Register getESI() {
return getIR().regpool.getPhysicalRegisterSet().getESI();
}
protected final OPT_Register getEDI() {
return getIR().regpool.getPhysicalRegisterSet().getEDI();
}
protected final OPT_Register getFPR(int n) {
return getIR().regpool.getPhysicalRegisterSet().getFPR(n);
}
protected final OPT_Operand myFP0() {
return new OPT_BURSManagedFPROperand(0);
}
protected final OPT_Operand myFP1() {
return new OPT_BURSManagedFPROperand(1);
}
protected final OPT_Register getST0() {
return getIR().regpool.getPhysicalRegisterSet().getST0();
}
/**
* Move op into a register operand if it isn't one already.
*/
private OPT_Operand asReg(OPT_Instruction s, OPT_Operator movop, OPT_Operand op) {
if (op.isRegister()) {
return op;
}
OPT_RegisterOperand tmp = regpool.makeTemp(op);
EMIT(CPOS(s, MIR_Move.create(movop, tmp, op)));
return tmp.copy();
}
/**
* Set the size field of the given memory operand and return it
*
* @param mo memory operand size to set
* @param size the new size
* @return mo
*/
protected final OPT_MemoryOperand setSize(OPT_MemoryOperand mo, int size) {
mo.size = (byte) size;
return mo;
}
/**
* Create a slot on the stack in memory for a conversion
*
* @param size for memory operand
* @return memory operand of slot in stack
*/
protected final OPT_Operand MO_CONV(byte size) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
return new OPT_StackLocationOperand(true, offset, size);
}
/**
* Create a 64bit slot on the stack in memory for a conversion and store the
* given long
*/
protected final void STORE_LONG_FOR_CONV(OPT_Operand op) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
if (op instanceof OPT_RegisterOperand) {
OPT_RegisterOperand hval = (OPT_RegisterOperand) op;
OPT_RegisterOperand lval = new OPT_RegisterOperand(regpool.getSecondReg(hval.getRegister()),
VM_TypeReference.Int);
EMIT(MIR_Move.create(IA32_MOV, new OPT_StackLocationOperand(true, offset + 4, DW), hval));
EMIT(MIR_Move.create(IA32_MOV, new OPT_StackLocationOperand(true, offset, DW), lval));
} else {
OPT_LongConstantOperand val = LC(op);
EMIT(MIR_Move.create(IA32_MOV, new OPT_StackLocationOperand(true, offset + 4, DW), IC(val.upper32())));
EMIT(MIR_Move.create(IA32_MOV, new OPT_StackLocationOperand(true, offset, DW), IC(val.lower32())));
}
}
/**
* Create memory operand to load from a given jtoc offset
*
* @param offset location in JTOC
* @param size of value in JTOC
* @return created memory operand
*/
static OPT_MemoryOperand loadFromJTOC(Offset offset, byte size) {
OPT_LocationOperand loc = new OPT_LocationOperand(offset);
OPT_Operand guard = TG();
return OPT_MemoryOperand.D(VM_Magic.getTocPointer().plus(offset), size, loc, guard);
}
/*
* IA32-specific emit rules that are complex enough that we didn't want to
* write them in the LIR2MIR.rules file. However, all expansions in this file
* are called during BURS and thus are constrained to generate nonbranching
* code (ie they can't create new basic blocks and/or do branching).
*/
/**
* Emit code to get a caught exception object into a register
*
* @param s the instruction to expand
*/
protected final void GET_EXCEPTION_OBJECT(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForCaughtException();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, DW);
EMIT(MIR_Move.mutate(s, IA32_MOV, Nullary.getResult(s), sl));
}
/**
* Emit code to move a value in a register to the stack location where a
* caught exception object is expected to be.
*
* @param s the instruction to expand
*/
protected final void SET_EXCEPTION_OBJECT(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForCaughtException();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, DW);
OPT_RegisterOperand obj = (OPT_RegisterOperand) CacheOp.getRef(s);
EMIT(MIR_Move.mutate(s, IA32_MOV, sl, obj));
}
/**
* Expansion of INT_2LONG
*
* @param s the instruction to expand
* @param result the result operand
* @param value the second operand
* @param signExtend should the value be sign or zero extended?
*/
protected final void INT_2LONG(OPT_Instruction s, OPT_RegisterOperand result,
OPT_Operand value, boolean signExtend) {
OPT_Register hr = result.getRegister();
OPT_Register lr = regpool.getSecondReg(hr);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(lr, VM_TypeReference.Int), value)));
if (signExtend) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(hr, VM_TypeReference.Int),
new OPT_RegisterOperand(lr, VM_TypeReference.Int))));
EMIT(MIR_BinaryAcc.mutate(s,IA32_SAR,
new OPT_RegisterOperand(hr, VM_TypeReference.Int),
IC(31)));
} else {
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(hr, VM_TypeReference.Int),
IC(0)));
}
}
/**
* Expansion of FLOAT_2INT and DOUBLE_2INT, using the FIST instruction. This
* expansion does some boolean logic and conditional moves in order to avoid
* changing the floating-point rounding mode or inserting branches. Other
* expansions are possible, and may be better?
*
* @param s the instruction to expand
* @param result the result operand
* @param value the second operand
*/
protected final void FPR_2INT(OPT_Instruction s, OPT_RegisterOperand result, OPT_Operand value) {
OPT_MemoryOperand M;
// Step 1: Get value to be converted into myFP0
// and in 'strict' IEEE mode.
if (value instanceof OPT_MemoryOperand) {
// value is in memory, all we have to do is load it
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), value)));
} else {
// sigh. value is an FP register. Unfortunately,
// SPECjbb requires some 'strict' FP semantics. Naturally, we don't
// normally implement strict semantics, but we try to slide by in
// order to pass the benchmark.
// In order to pass SPECjbb, it turns out we need to enforce 'strict'
// semantics before doing a particular f2int conversion. To do this
// we must have a store/load sequence to cause IEEE rounding.
if (value instanceof OPT_BURSManagedFPROperand) {
if (VM.VerifyAssertions) {
VM._assert(value.similar(myFP0()));
}
EMIT(CPOS(s, MIR_Move.create(IA32_FSTP, MO_CONV(DW), value)));
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), MO_CONV(DW))));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, MO_CONV(DW), value)));
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), MO_CONV(DW))));
}
}
// FP Stack: myFP0 = value
EMIT(CPOS(s, MIR_Move.create(IA32_FIST, MO_CONV(DW), myFP0())));
// MO_CONV now holds myFP0 converted to an integer (round-toward nearest)
// FP Stack: myFP0 == value
// isPositive == 1 iff 0.0 < value
// isNegative == 1 iff 0.0 > value
OPT_Register one = regpool.getInteger();
OPT_Register isPositive = regpool.getInteger();
OPT_Register isNegative = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(one, VM_TypeReference.Int), IC(1))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(isPositive, VM_TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(isNegative, VM_TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_Nullary.create(IA32_FLDZ, myFP0())));
// FP Stack: myFP0 = 0.0; myFP1 = value
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
// FP Stack: myFP0 = value
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new OPT_RegisterOperand(isPositive, VM_TypeReference.Int),
new OPT_RegisterOperand(one, VM_TypeReference.Int),
OPT_IA32ConditionOperand.LLT())));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new OPT_RegisterOperand(isNegative, VM_TypeReference.Int),
new OPT_RegisterOperand(one, VM_TypeReference.Int),
OPT_IA32ConditionOperand.LGT())));
EMIT(CPOS(s, MIR_Move.create(IA32_FILD, myFP0(), MO_CONV(DW))));
// FP Stack: myFP0 = round(value), myFP1 = value
// addee = 1 iff round(x) < x
// subtractee = 1 iff round(x) > x
OPT_Register addee = regpool.getInteger();
OPT_Register subtractee = regpool.getInteger();
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
// FP Stack: myFP0 = value
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(addee, VM_TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(subtractee, VM_TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new OPT_RegisterOperand(addee, VM_TypeReference.Int),
new OPT_RegisterOperand(one, VM_TypeReference.Int),
OPT_IA32ConditionOperand.LLT())));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new OPT_RegisterOperand(subtractee, VM_TypeReference.Int),
new OPT_RegisterOperand(one, VM_TypeReference.Int),
OPT_IA32ConditionOperand.LGT())));
// Now a little tricky part.
// We will add 1 iff isNegative and x > round(x)
// We will subtract 1 iff isPositive and x < round(x)
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
new OPT_RegisterOperand(addee, VM_TypeReference.Int),
new OPT_RegisterOperand(isNegative, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
new OPT_RegisterOperand(subtractee, VM_TypeReference.Int),
new OPT_RegisterOperand(isPositive, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), MO_CONV(DW))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD, result.copy(), new OPT_RegisterOperand(addee, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, result.copy(), new OPT_RegisterOperand(subtractee, VM_TypeReference.Int))));
// Compare myFP0 with (double)Integer.MAX_VALUE
M = OPT_MemoryOperand.D(VM_Magic.getTocPointer().plus(VM_Entrypoints.maxintField.getOffset()), QW, null, null);
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), M)));
// FP Stack: myFP0 = (double)Integer.MAX_VALUE; myFP1 = value
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
// FP Stack: myFP0 = value
// If MAX_VALUE < value, then result := MAX_INT
OPT_Register maxInt = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(maxInt, VM_TypeReference.Int), IC(Integer.MAX_VALUE))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
result.copy(),
new OPT_RegisterOperand(maxInt, VM_TypeReference.Int),
OPT_IA32ConditionOperand.LLT())));
// Compare myFP0 with (double)Integer.MIN_VALUE
M = OPT_MemoryOperand.D(VM_Magic.getTocPointer().plus(VM_Entrypoints.minintField.getOffset()), QW, null, null);
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), M)));
// FP Stack: myFP0 = (double)Integer.MIN_VALUE; myFP1 = value
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
// FP Stack: myFP0 = value
// If MIN_VALUE > value, then result := MIN_INT
OPT_Register minInt = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(minInt, VM_TypeReference.Int), IC(Integer.MIN_VALUE))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
result.copy(),
new OPT_RegisterOperand(minInt, VM_TypeReference.Int),
OPT_IA32ConditionOperand.LGT())));
// Set condition flags: set PE iff myFP0 is a NaN
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP0())));
// FP Stack: back to original level (all BURS managed slots freed)
// If FP0 was classified as a NaN, then result := 0
OPT_Register zero = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(zero, VM_TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
result.copy(),
new OPT_RegisterOperand(zero, VM_TypeReference.Int),
OPT_IA32ConditionOperand.PE())));
}
/**
* Emit code to move 64 bits from FPRs to GPRs
*/
protected final void FPR2GPR_64(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, QW);
OPT_StackLocationOperand sl1 = new OPT_StackLocationOperand(true, offset + 4, DW);
OPT_StackLocationOperand sl2 = new OPT_StackLocationOperand(true, offset, DW);
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, sl, Unary.getVal(s))));
OPT_RegisterOperand i1 = Unary.getResult(s);
OPT_RegisterOperand i2 = new OPT_RegisterOperand(regpool
.getSecondReg(i1.getRegister()), VM_TypeReference.Int);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, i1, sl1)));
EMIT(MIR_Move.mutate(s, IA32_MOV, i2, sl2));
}
/**
* Emit code to move 64 bits from GPRs to FPRs
*/
protected final void GPR2FPR_64(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, QW);
OPT_StackLocationOperand sl1 = new OPT_StackLocationOperand(true, offset + 4, DW);
OPT_StackLocationOperand sl2 = new OPT_StackLocationOperand(true, offset, DW);
OPT_Operand i1, i2;
OPT_Operand val = Unary.getVal(s);
if (val instanceof OPT_RegisterOperand) {
OPT_RegisterOperand rval = (OPT_RegisterOperand) val;
i1 = val;
i2 = new OPT_RegisterOperand(regpool.getSecondReg(rval.getRegister()), VM_TypeReference.Int);
} else {
OPT_LongConstantOperand rhs = (OPT_LongConstantOperand) val;
i1 = IC(rhs.upper32());
i2 = IC(rhs.lower32());
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl1, i1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl2, i2)));
EMIT(MIR_Move.mutate(s, IA32_FMOV, Unary.getResult(s), sl));
}
/**
* Returns the appropriate move operator based on the type of operand.
*/
protected final OPT_Operator SSE2_MOVE(OPT_Operand o) {
return o.isFloat() ? IA32_MOVSS : IA32_MOVSD;
}
/**
* Returns the size based on the type of operand.
*/
protected final byte SSE2_SIZE(OPT_Operand o) {
return o.isFloat() ? DW : QW;
}
/**
* Performs a long -> double/float conversion using x87 and marshalls back to XMMs.
*/
protected final void SSE2_X87_FROMLONG(OPT_Instruction s) {
OPT_Operand result = Unary.getResult(s);
STORE_LONG_FOR_CONV(Unary.getVal(s));
// conversion space allocated, contains the long to load.
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, SSE2_SIZE(result));
OPT_RegisterOperand st0 = new OPT_RegisterOperand(getST0(), result.getType());
EMIT(CPOS(s, MIR_Move.create(IA32_FILD, st0, sl)));
EMIT(CPOS(s, MIR_Move.create(IA32_FSTP, sl.copy(), st0.copyD2U())));
EMIT(CPOS(s, MIR_Move.mutate(s, SSE2_MOVE(result), result, sl.copy())));
}
/**
* Performs a long -> double/float conversion using x87 and marshalls between to XMMs.
*/
protected final void SSE2_X87_REM(OPT_Instruction s) {
OPT_Operand result = Binary.getClearResult(s);
OPT_RegisterOperand st0 = new OPT_RegisterOperand(getST0(), result.getType());
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, SSE2_SIZE(result));
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), sl, Binary.getVal2(s))));
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, st0, sl.copy())));
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), sl.copy(), Binary.getVal1(s))));
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, st0.copy(), sl.copy())));
// The parameters to FPREM actually get ignored (implied ST0/ST1)
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_FPREM, st0.copy(), st0.copy())));
EMIT(CPOS(s, MIR_Move.create(IA32_FSTP, sl.copy(), st0.copy())));
EMIT(MIR_Move.mutate(s, SSE2_MOVE(result), result, sl.copy()));
}
/**
* Emit code to move 64 bits from SSE2 FPRs to GPRs
*/
protected final void SSE2_FPR2GPR_64(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, QW);
OPT_StackLocationOperand sl1 = new OPT_StackLocationOperand(true, offset + 4, DW);
OPT_StackLocationOperand sl2 = new OPT_StackLocationOperand(true, offset, DW);
EMIT(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, Unary.getVal(s))));
OPT_RegisterOperand i1 = Unary.getResult(s);
OPT_RegisterOperand i2 = new OPT_RegisterOperand(regpool
.getSecondReg(i1.getRegister()), VM_TypeReference.Int);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, i1, sl1)));
EMIT(MIR_Move.mutate(s, IA32_MOV, i2, sl2));
}
/**
* Emit code to move 64 bits from GPRs to SSE2 FPRs
*/
protected final void SSE2_GPR2FPR_64(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, QW);
OPT_StackLocationOperand sl1 = new OPT_StackLocationOperand(true, offset + 4, DW);
OPT_StackLocationOperand sl2 = new OPT_StackLocationOperand(true, offset, DW);
OPT_Operand i1, i2;
OPT_Operand val = Unary.getVal(s);
if (val instanceof OPT_RegisterOperand) {
OPT_RegisterOperand rval = (OPT_RegisterOperand) val;
i1 = val;
i2 = new OPT_RegisterOperand(regpool.getSecondReg(rval.getRegister()), VM_TypeReference.Int);
} else {
OPT_LongConstantOperand rhs = (OPT_LongConstantOperand) val;
i1 = IC(rhs.upper32());
i2 = IC(rhs.lower32());
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl1, i1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl2, i2)));
EMIT(MIR_Move.mutate(s, IA32_MOVSD, Unary.getResult(s), sl));
}
/**
* Emit code to move 32 bits from FPRs to GPRs
*/
protected final void SSE2_FPR2GPR_32(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, DW);
EMIT(CPOS(s, MIR_Move.create(IA32_MOVSS, sl, Unary.getVal(s))));
EMIT(MIR_Move.mutate(s, IA32_MOV, Unary.getResult(s), sl.copy()));
}
/**
* Emit code to move 32 bits from GPRs to FPRs
*/
protected final void SSE2_GPR2FPR_32(OPT_Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
OPT_StackLocationOperand sl = new OPT_StackLocationOperand(true, offset, DW);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl, Unary.getVal(s))));
EMIT(MIR_Move.mutate(s, IA32_MOVSS, Unary.getResult(s), sl.copy()));
}
/**
* BURS expansion of a commutative SSE2 operation.
*/
protected void SSE2_COP(OPT_Operator operator, OPT_Instruction s, OPT_Operand result, OPT_Operand val1, OPT_Operand val2) {
if(VM.VerifyAssertions) VM._assert(result.isRegister());
// Swap operands to reduce chance of generating a move or to normalize
// constants into val2
if (val2.similar(result)) {
OPT_Operand temp = val1;
val1 = val2;
val2 = temp;
}
// Do we need to move prior to the operator - result = val1
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result.copy(), val1)));
}
EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
}
/**
* BURS expansion of a non commutative SSE2 operation.
*/
protected void SSE2_NCOP(OPT_Operator operator, OPT_Instruction s, OPT_Operand result, OPT_Operand val1, OPT_Operand val2) {
if(VM.VerifyAssertions) VM._assert(result.isRegister());
if (result.similar(val1)) {
// Straight forward case where instruction is already in accumulate form
EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
} else if (!result.similar(val2)) {
// Move first operand to result and perform operator on result, if
// possible redundant moves should be remove by register allocator
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result.copy(), val1)));
EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
} else {
// Potential to clobber second operand during move to result. Use a
// temporary register to perform the operation and rely on register
// allocator to remove redundant moves
OPT_RegisterOperand temp = regpool.makeTemp(result);
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), temp, val1)));
EMIT(MIR_BinaryAcc.mutate(s, operator, temp.copyRO(), val2));
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result, temp.copyRO())));
}
}
/**
* Expansion of SSE2 negation ops
*/
protected final void SSE2_NEG(OPT_Operator xorOp, OPT_Operator subOp, OPT_Instruction s, OPT_Operand result, OPT_Operand value) {
if(VM.VerifyAssertions) VM._assert(result.isRegister());
if (!result.similar(value)) {
EMIT(CPOS(s, MIR_BinaryAcc.create(xorOp, result.copy(), result.copy())));
EMIT(MIR_BinaryAcc.mutate(s, subOp, result, value));
} else {
OPT_RegisterOperand temp = regpool.makeTemp(value.getType());
EMIT(CPOS(s, MIR_BinaryAcc.create(xorOp, temp.copyRO(), temp)));
EMIT(MIR_BinaryAcc.mutate(s, subOp, temp.copyRO(), value));
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result, temp.copyRO())));
}
}
/**
* Expansion of SSE2 conversions double <-> float
*/
protected final void SSE2_CONV(OPT_Operator op, OPT_Instruction s, OPT_Operand result, OPT_Operand value) {
if(VM.VerifyAssertions) VM._assert(result.isRegister());
if(VM.VerifyAssertions) VM._assert(value.isRegister());
EMIT(MIR_Unary.mutate(s, op, result, value));
}
/**
* Expansion of SSE2 comparison operations
*/
protected final void SSE2_IFCMP(OPT_Operator op, OPT_Instruction s, OPT_Operand val1, OPT_Operand val2) {
EMIT(CPOS(s, MIR_Compare.create(op, val1, val2)));
EMIT(s); // OPT_ComplexLIR2MIRExpansion will handle rest of the work.
}
/**
* Expansion of SSE2 floating point constant loads
*/
protected final void SSE2_FPCONSTANT(OPT_Instruction s) {
EMIT(MIR_Move.mutate(s, SSE2_MOVE(Binary.getResult(s)), Binary.getResult(s), MO_MC(s)));
}
/**
* Expansion of INT_DIV and INT_REM
*
* @param s the instruction to expand
* @param result the result operand
* @param val1 the first operand
* @param val2 the second operand
* @param isDiv true for div, false for rem
*/
protected final void INT_DIVIDES(OPT_Instruction s, OPT_RegisterOperand result, OPT_Operand val1, OPT_Operand val2,
boolean isDiv) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int), val1)));
EMIT(CPOS(s, MIR_ConvertDW2QW.create(IA32_CDQ,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
if (val2 instanceof OPT_IntConstantOperand) {
OPT_RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2)));
val2 = temp.copyRO();
}
EMIT(MIR_Divide.mutate(s,
IA32_IDIV,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
val2,
GuardedBinary.getGuard(s)));
if (isDiv) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
}
}
/**
* Expansion of LONG_ADD
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
*/
protected final void LONG_ADD(OPT_Instruction s, OPT_RegisterOperand result,
OPT_Operand value1, OPT_Operand value2) {
// The value of value1 should be identical to result, to avoid moves, and a
// register in the case of addition with a constant
if ((value2.similar(result)) || value1.isLongConstant()) {
OPT_Operand temp = value1;
value1 = value2;
value2 = temp;
}
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
if (value1.isRegister() && value2.isRegister()) {
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_Register rhsReg2 = ((OPT_RegisterOperand) value2).getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
// Do we need to move prior to the add - result = value1
if (!value1.similar(result)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// Perform add - result += value2
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_ADC,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (value1.isRegister()){
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_LongConstantOperand rhs2 = (OPT_LongConstantOperand) value2;
int low = rhs2.lower32();
int high = rhs2.upper32();
// Do we need to move prior to the add - result = value1
if (!value1.similar(result)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// Perform add - result += value2
if (low == 0) {
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_ADC,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + value1 + "+" + value2);
}
}
/**
* Expansion of LONG_SUB
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
*/
protected final void LONG_SUB(OPT_Instruction s, OPT_Operand result,
OPT_Operand val1, OPT_Operand val2) {
if (result.similar(val1)) {
// Straight forward case where instruction is already in accumulate form
if (result.isRegister()) {
OPT_Register lhsReg = result.asRegister().getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
if (val2.isRegister()) {
OPT_Register rhsReg2 = val2.asRegister().getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (val2.isLongConstant()) {
OPT_LongConstantOperand rhs2 = val2.asLongConstant();
int low = rhs2.lower32();
int high = rhs2.upper32();
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
} else if (!result.similar(val2)) {
// Move first operand to result and perform operator on result, if
// possible redundant moves should be remove by register allocator
if (result.isRegister()) {
OPT_Register lhsReg = result.asRegister().getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
// Move val1 into result
if (val1.isRegister()) {
OPT_Register rhsReg1 = val1.asRegister().getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
} else if (val1.isLongConstant()) {
OPT_LongConstantOperand rhs1 = val1.asLongConstant();
int low = rhs1.lower32();
int high = rhs1.upper32();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
// Perform subtract
if (val2.isRegister()) {
OPT_Register rhsReg2 = val2.asRegister().getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (val2.isLongConstant()) {
OPT_LongConstantOperand rhs2 = val2.asLongConstant();
int low = rhs2.lower32();
int high = rhs2.upper32();
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
} else {
// Potential to clobber second operand during move to result. Use a
// temporary register to perform the operation and rely on register
// allocator to remove redundant moves
OPT_RegisterOperand temp1 = regpool.makeTempInt();
OPT_RegisterOperand temp2 = regpool.makeTempInt();
// Move val1 into temp
if (val1.isRegister()) {
OPT_Register rhsReg1 = val1.asRegister().getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
temp1,
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
temp2,
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
} else if (val1.isLongConstant()) {
OPT_LongConstantOperand rhs1 = val1.asLongConstant();
int low = rhs1.lower32();
int high = rhs1.upper32();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
temp1,
IC(low))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
temp2,
IC(high))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
// Perform subtract
if (val2.isRegister()) {
OPT_Register rhsReg2 = val2.asRegister().getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
temp1.copyRO(),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB,
temp2.copyRO(),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (val2.isLongConstant()) {
OPT_LongConstantOperand rhs2 = val2.asLongConstant();
int low = rhs2.lower32();
int high = rhs2.upper32();
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
temp1.copyRO(),
IC(low))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB,
temp2.copyRO(),
IC(high))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
// Move result back
if (result.isRegister()) {
OPT_Register lhsReg = result.asRegister().getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
temp1.copyRO())));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
temp2.copyRO())));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "-" + val2);
}
}
}
/**
* Expansion of LONG_MUL
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
*/
protected final void LONG_MUL(OPT_Instruction s, OPT_RegisterOperand result,
OPT_Operand value1, OPT_Operand value2) {
if (value2.isRegister()) {
// Leave for complex LIR2MIR expansion as the most efficient form requires
// a branch
if (VM.VerifyAssertions) VM._assert(Binary.getResult(s).similar(result) &&
Binary.getVal1(s).similar(value1) && Binary.getVal2(s).similar(value2));
EMIT(s);
} else {
// The value of value1 should be identical to result, to avoid moves, and a
// register in the case of multiplication with a constant
if ((value2.similar(result)) || value1.isLongConstant()) {
OPT_Operand temp = value1;
value1 = value2;
value2 = temp;
}
if (VM.VerifyAssertions) VM._assert(value1.isRegister() && value2.isLongConstant());
// In general, (a,b) * (c,d) = (l(a imul d)+l(b imul c)+u(b mul d), l(b mul d))
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
OPT_LongConstantOperand rhs2 = (OPT_LongConstantOperand) value2;
OPT_Register rhsReg1 = value1.asRegister().getRegister(); // a
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1); // b
int high2 = rhs2.upper32(); // c
int low2 = rhs2.lower32(); // d
// We only have to handle those cases that OPT_Simplifier wouldn't get.
// OPT_Simplifier catches
// high low
// 0 0 (0L)
// 0 1 (1L)
// -1 -1 (-1L)
// So, the possible cases we need to handle here:
// -1 0
// -1 1
// -1 *
// 0 -1
// 0 *
// 1 -1
// 1 0
// 1 1
// 1 *
// * -1
// * 0
// * 1
// * *
// (where * is something other than -1,0,1)
if (high2 == -1) {
if (low2 == 0) {
// -1, 0
// CLAIM: (a,b) * (-1,0) = (-b,0)
if (VM.VerifyAssertions) VM._assert(lhsReg != lowrhsReg1);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0))));
} else if (low2 == 1) {
// -1, 1
// CLAIM: (a,b) * (-1,1) = (a-b,b)
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
} else {
// -1, *
// CLAIM: (a,b) * (-1, d) = (l(a imul d)-b+u(b mul d), l(b mul d))
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
}
} else if (high2 == 0) {
if (low2 == -1) {
// 0, -1
// CLAIM: (a,b) * (0,-1) = (b-(a+(b!=0?1:0)),-b)
// avoid clobbering a and b by using tmp
OPT_Register tmp = regpool.getInteger();
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
} else {
// 0, *
// CLAIM: (a,b) * (0,d) = (l(a imul d)+u(b mul d), l(b mul d))
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
}
} else if (high2 == 1) {
if (low2 == -1) {
// 1, -1
// CLAIM: (a,b) * (1,-1) = (2b-(a+(b!=0?1:0)),-b)
// avoid clobbering a and b by using tmp
OPT_Register tmp = regpool.getInteger();
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
} else if (low2 == 0) {
// 1, 0
// CLAIM: (x,y) * (1,0) = (y,0)
// NB we should have simplified this LONG_MUL to a LONG_SHIFT
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0))));
} else if (low2 == 1) {
// 1, 1
// CLAIM: (x,y) * (1,1) = (x+y,y)
// NB we should have simplified this LONG_MUL to a LONG_SHIFT and LONG_ADDs
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
} else {
// 1, *
// CLAIM: (a,b) * (1,d) = (l(a imul d)+b+u(b mul d), l(b mul d))
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
}
} else {
if (low2 == -1) {
// *, -1
// CLAIM: (a,b) * (c, -1) = ((b+1)*c - (a + b==0?1:0), -b)
// avoid clobbering a and b by using tmp
OPT_Register tmp = regpool.getInteger();
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(1))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
} else if (low2 == 0) {
// *, 0
// CLAIM: (a,b) * (c,0) = (l(b imul c),0)
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0))));
} else if (low2 == 1) {
// *, 1
// CLAIM: (x,y) * (z,1) = (l(y imul z)+x,y)
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_Move.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
} else {
// *, * can't do anything interesting and both operands have non-zero words
// (a,b) * (c,d) = (l(a imul d)+l(b imul c)+u(b mul d), l(b mul d))
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(low2))));
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
}
}
}
}
/**
* Expansion of LONG_NEG
*
* @param s the instruction to expand
* @param result the result operand
* @param value the first operand
*/
protected final void LONG_NEG(OPT_Instruction s, OPT_RegisterOperand result, OPT_Operand value) {
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
// Move value into result if its not already
if (!result.similar(value)){
if (value.isRegister()) {
OPT_Register rhsReg = value.asRegister().getRegister();
OPT_Register lowrhsReg = regpool.getSecondReg(rhsReg);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg, VM_TypeReference.Int))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "= -" + value);
}
}
// Perform negation
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(-1))));
}
/**
* Expansion of LONG_NOT
*
* @param s the instruction to expand
* @param result the result operand
* @param value the first operand
*/
protected final void LONG_NOT(OPT_Instruction s, OPT_RegisterOperand result, OPT_Operand value) {
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
// Move value into result if its not already
if (!result.similar(value)){
if (value.isRegister()) {
OPT_Register rhsReg = value.asRegister().getRegister();
OPT_Register lowrhsReg = regpool.getSecondReg(rhsReg);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg, VM_TypeReference.Int))));
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "= ~" + value);
}
}
// Perform not
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.mutate(s, IA32_NOT,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
}
/**
* Expansion of LONG_AND
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
*/
protected final void LONG_AND(OPT_Instruction s, OPT_RegisterOperand result,
OPT_Operand value1, OPT_Operand value2) {
// The value of value1 should be identical to result, to avoid moves, and a
// register in the case of addition with a constant
if ((value2.similar(result)) || value1.isLongConstant()) {
OPT_Operand temp = value1;
value1 = value2;
value2 = temp;
}
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
if (value1.isRegister() && value2.isRegister()) {
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_Register rhsReg2 = ((OPT_RegisterOperand) value2).getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
// Do we need to move prior to the and - result = value1
if (!value1.similar(result)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// Perform and - result &= value2
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_AND,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (value1.isRegister()){
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_LongConstantOperand rhs2 = (OPT_LongConstantOperand) value2;
int low = rhs2.lower32();
int high = rhs2.upper32();
// Do we need to move prior to the and - result = value1
if (!value1.similar(result)) {
if (low != 0) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
if (high != 0) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
}
// Perform and - result &= value2
if (low == 0) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0))));
} else if (low == -1) {
// nop
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
}
if (high == 0) {
EMIT(CPOS(s, MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(0))));
} else if (high == -1) {
// nop
} else {
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_AND,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + value1 + "+" + value2);
}
}
/**
* Expansion of LONG_OR
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
*/
protected final void LONG_OR(OPT_Instruction s, OPT_RegisterOperand result,
OPT_Operand value1, OPT_Operand value2) {
// The value of value1 should be identical to result, to avoid moves, and a
// register in the case of addition with a constant
if ((value2.similar(result)) || value1.isLongConstant()) {
OPT_Operand temp = value1;
value1 = value2;
value2 = temp;
}
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
if (value1.isRegister() && value2.isRegister()) {
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_Register rhsReg2 = ((OPT_RegisterOperand) value2).getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
// Do we need to move prior to the and - result = value1
if (!value1.similar(result)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// Perform or - result |= value2
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_OR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (value1.isRegister()){
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_LongConstantOperand rhs2 = (OPT_LongConstantOperand) value2;
int low = rhs2.lower32();
int high = rhs2.upper32();
// Do we need to move prior to the and - result = value1
if (!value1.similar(result)) {
if (low != -1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
if (high != -1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
}
// Perform or - result |= value2
if (low == 0) {
// nop
} else if (low == -1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(-1))));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
}
if (high == 0) {
// nop
} else if (high == -1) {
EMIT(CPOS(s, MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(-1))));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_OR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + value1 + "+" + value2);
}
}
/**
* Expansion of LONG_XOR
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
*/
protected final void LONG_XOR(OPT_Instruction s, OPT_RegisterOperand result,
OPT_Operand value1, OPT_Operand value2) {
// The value of value1 should be identical to result, to avoid moves, and a
// register in the case of addition with a constant
if ((value2.similar(result)) || value1.isLongConstant()) {
OPT_Operand temp = value1;
value1 = value2;
value2 = temp;
}
OPT_Register lhsReg = result.getRegister();
OPT_Register lowlhsReg = regpool.getSecondReg(lhsReg);
if (value1.isRegister() && value2.isRegister()) {
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_Register rhsReg2 = ((OPT_RegisterOperand) value2).getRegister();
OPT_Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
// Do we need to move prior to the and - result = value1
if (!value1.similar(result)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// Perform or - result |= value2
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_XOR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg2, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_XOR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg2, VM_TypeReference.Int))));
} else if (value1.isRegister()){
OPT_Register rhsReg1 = ((OPT_RegisterOperand) value1).getRegister();
OPT_Register lowrhsReg1 = regpool.getSecondReg(rhsReg1);
OPT_LongConstantOperand rhs2 = (OPT_LongConstantOperand) value2;
int low = rhs2.lower32();
int high = rhs2.upper32();
// Do we need to move prior to the and - result = value1
if (!value1.similar(result)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// Perform xor - result ^= value2
if (low == 0) {
// nop
} else if (low == -1) {
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_XOR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(low))));
}
if (high == 0) {
// nop
} else if (high == -1) {
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int))));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_XOR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(high))));
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + value1 + "+" + value2);
}
}
/**
* Expansion of LONG_SHL
* @param s the instruction to expand
* @param result the result operand
* @param val1 the shifted operand
* @param val2 the shift amount operand
* @param maskWith3f should the shift operand by masked with 0x3f? This is
* default behaviour on Intel but it differs from how we combine
* shift operands in HIR
*/
protected final void LONG_SHL(OPT_Instruction s, OPT_Operand result,
OPT_Operand val1, OPT_Operand val2, boolean maskWith3f) {
if (!val2.isIntConstant()) {
// the most efficient form of expanding a shift by a variable amount
// requires a branch so leave for complex operators
// NB if !maskWith3f - we assume that a mask with 0x3F was required as
// no optimizations currently exploits shift by registers of > 63
// returning 0
Binary.mutate(s, LONG_SHL, result.asRegister(), val1, val2);
EMIT(s);
} else if (result.isRegister()) {
int shift = val2.asIntConstant().value;
OPT_Register lhsReg = result.asRegister().getRegister();
OPT_Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
OPT_Register rhsReg1 = val1.asRegister().getRegister();
OPT_Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
if (shift == 0) {
// operation is a nop.
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_ADD,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int))));
EMIT(MIR_BinaryAcc.mutate(s,
IA32_ADC,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int)));
} else if (shift == 2) {
// bits to shift in: tmp = lowrhsReg >> 30
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(30))));
// compute top half: lhsReg = (rhsReg1 << 2) + tmp
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
OPT_MemoryOperand.BIS(new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int),
(byte)2, (byte)4, null, null))));
// compute bottom half: lowlhsReg = lowlhsReg << 2
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_MemoryOperand(null, // base
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int), //index
(byte)2, // scale
Offset.zero(), // displacement
(byte)4, // size
null, // location
null // guard
))));
} else if (shift == 3) {
// bits to shift in: tmp = lowrhsReg >>> 29
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(29))));
// compute top half: lhsReg = (rhsReg1 << 3) + tmp
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
OPT_MemoryOperand.BIS(new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int),
(byte)3, (byte)4, null, null))));
// compute bottom half: lowlhsReg = lowlhsReg << 3
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_MemoryOperand(null, // base
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int), //index
(byte)3, // scale
Offset.zero(), // displacement
(byte)4, // size
null, // location
null // guard
))));
} else if (shift < 32) {
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// bits to shift in: tmp = lowrhsReg >>> (32 - shift)
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(32 - shift))));
// compute top half: lhsReg = (lhsReg1 << shift) | tmp
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(shift))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_OR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
// compute bottom half: lowlhsReg = lowlhsReg << shift
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHL,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(shift)));
} else if (shift == 32) {
// lhsReg = lowrhsReg1
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0)));
} else if (shift == 33) {
// lhsReg = lowrhsReg1 << 1
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_MemoryOperand(null, // base
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int), //index
(byte)1, // scale
Offset.zero(), // displacement
(byte)4, // size
null, // location
null // guard
))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0)));
} else if (shift == 34) {
// lhsReg = lowrhsReg1 << 2
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_MemoryOperand(null, // base
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int), //index
(byte)2, // scale
Offset.zero(), // displacement
(byte)4, // size
null, // location
null // guard
))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0)));
} else if (shift == 35) {
// lhsReg = lowrhsReg1 << 3
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_MemoryOperand(null, // base
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int), //index
(byte)3, // scale
Offset.zero(), // displacement
(byte)4, // size
null, // location
null // guard
))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0)));
} else {
if ((maskWith3f) || (shift < 64)){
// lhsReg = lowrhsReg1 << ((shift - 32) & 0x1f)
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC((shift-32) & 0x1F))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0)));
} else {
// lhsReg = 0
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(0))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0)));
}
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + "<<" + val2);
}
}
/**
* Expansion of LONG_SHR
* @param s the instruction to expand
* @param result the result operand
* @param val1 the shifted operand
* @param val2 the shift amount operand
* @param maskWith3f should the shift operand by masked with 0x3f? This is
* default behaviour on Intel but it differs from how we combine
* shift operands in HIR
*/
protected final void LONG_SHR(OPT_Instruction s, OPT_Operand result,
OPT_Operand val1, OPT_Operand val2, boolean maskWith3f) {
if (!val2.isIntConstant()) {
// the most efficient form of expanding a shift by a variable amount
// requires a branch so leave for complex operators
// NB if !maskWith3f - we assume that a mask with 0x3F was required as
// no optimizations currently exploits shift by registers of > 63
// returning 0
Binary.mutate(s, LONG_SHR, result.asRegister(), val1, val2);
EMIT(s);
} else if (result.isRegister()) {
int shift = val2.asIntConstant().value;
if (maskWith3f) {
shift = shift & 0x3F;
}
OPT_Register lhsReg = result.asRegister().getRegister();
OPT_Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
OPT_Register rhsReg1 = val1.asRegister().getRegister();
OPT_Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
if (shift == 0) {
// operation is a nop.
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// lhsReg = lhsReg >> 1
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(1))));
// lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(1)));
} else if (shift < 32) {
// bits to shift in: tmp = rhsReg << (32 - shift)
// TODO: use of LEA for SHL
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(32 - shift))));
// compute bottom half: lowlhsReg = (lowlhsReg1 >>> shift) | tmp
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(shift))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_OR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
// compute top half: lhsReg = lhsReg >> shift
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SAR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(shift)));
} else if (shift == 32) {
// lowlhsReg = rhsReg1
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int)));
// lhsReg = rhsReg1 >> 31
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(31))));
} else {
if ((!maskWith3f && (shift >= 0x3F))||
(maskWith3f && ((shift & 0x3F) == 0x3F))) {
// lhsReg = rhsReg1 >> 31
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(31))));
// lowlhsReg = lhsReg
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int)));
} else {
// lhsReg = rhsReg1 >> 31
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(31))));
// lowlhsReg = rhsReg1 >> shift
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int)));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC((shift - 32) & 0x3F))));
}
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + ">>" + val2);
}
}
/**
* Expansion of LONG_USHR
* @param s the instruction to expand
* @param result the result operand
* @param val1 the shifted operand
* @param val2 the shift amount operand
* @param maskWith3f should the shift operand by masked with 0x3f? This is
* default behaviour on Intel but it differs from how we combine
* shift operands in HIR
*/
protected final void LONG_USHR(OPT_Instruction s, OPT_Operand result,
OPT_Operand val1, OPT_Operand val2, boolean maskWith3f) {
if (!val2.isIntConstant()) {
// the most efficient form of expanding a shift by a variable amount
// requires a branch so leave for complex operators
// NB if !maskWith3f - we assume that a mask with 0x3F was required as
// no optimizations currently exploits shift by registers of > 63
// returning 0
Binary.mutate(s, LONG_USHR, result.asRegister(), val1, val2);
EMIT(s);
} else if (result.isRegister()) {
int shift = val2.asIntConstant().value;
if (maskWith3f) {
shift = shift & 0x3F;
}
OPT_Register lhsReg = result.asRegister().getRegister();
OPT_Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
OPT_Register rhsReg1 = val1.asRegister().getRegister();
OPT_Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
if (shift == 0) {
// operation is a nop.
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
// lhsReg = lhsReg >>> 1
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(1))));
// lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(1)));
} else if (shift < 32) {
// bits to shift in: tmp = rhsReg << (32 - shift)
// TODO: use LEA for SHL operator
OPT_Register tmp = regpool.getInteger();
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new OPT_RegisterOperand(tmp, VM_TypeReference.Int),
IC(32 - shift))));
// compute bottom half: lowlhsReg = (lowlhsReg1 >>> shift) | tmp
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(lowrhsReg1, VM_TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(shift))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_OR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(tmp, VM_TypeReference.Int))));
// compute top half: lhsReg = lhsReg >>> shift
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(shift)));
} else if (shift == 32) {
// lowlhsReg = rhsReg1
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int)));
// lhsReg = 0
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(0))));
} else {
if (maskWith3f || (shift < 64)) {
// lowlhsReg = rhsReg1 >>> (shift & 0x1F)
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
new OPT_RegisterOperand(rhsReg1, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(shift&0x1F))));
} else {
// lowlhsReg = 0
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowlhsReg, VM_TypeReference.Int),
IC(0))));
}
// lhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new OPT_RegisterOperand(lhsReg, VM_TypeReference.Int),
IC(0)));
}
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers",
"unexpected parameters: " + result + "=" + val1 + ">>" + val2);
}
}
/**
* Expansion of RDTSC (called GET_TIME_BASE for consistency with PPC)
*
* @param s the instruction to expand
* @param result the result/first operand
*/
protected final void GET_TIME_BASE(OPT_Instruction s,
OPT_RegisterOperand result) {
OPT_Register highReg = result.getRegister();
OPT_Register lowReg = regpool.getSecondReg(highReg);
EMIT(CPOS(s, MIR_RDTSC.create(IA32_RDTSC,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(lowReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new OPT_RegisterOperand(highReg, VM_TypeReference.Int),
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int))));
}
/**
* Expansion of LONG_CMP: compare to values and set result to -1, 0, 1 for <, =, >,
* respectively
*
* @param s the compare instruction
* @param res the result/first operand
* @param val1 the first value
* @param val2 the second value
*/
protected final void LONG_CMP(OPT_Instruction s, OPT_RegisterOperand res, OPT_Operand val1, OPT_Operand val2) {
OPT_RegisterOperand one = regpool.makeTempInt();
OPT_RegisterOperand lone = regpool.makeTempInt();
OPT_Operand two, ltwo;
if (val1 instanceof OPT_RegisterOperand) {
OPT_Register val1_reg = val1.asRegister().getRegister();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new OPT_RegisterOperand(val1_reg, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
lone,
new OPT_RegisterOperand(regpool.getSecondReg(val1_reg), VM_TypeReference.Int))));
} else {
OPT_LongConstantOperand tmp = (OPT_LongConstantOperand) val1;
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, IC(tmp.upper32()))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lone, IC(tmp.lower32()))));
}
if (val2 instanceof OPT_RegisterOperand) {
two = val2;
ltwo = L(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()));
} else {
OPT_LongConstantOperand tmp = (OPT_LongConstantOperand) val2;
two = IC(tmp.upper32());
ltwo = IC(tmp.lower32());
}
EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, lone.copyRO(), ltwo)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
EMIT(CPOS(s, MIR_Set
.create(IA32_SET__B, res, OPT_IA32ConditionOperand.LT()))); // res =
// (val1 < val2) ? 1 :0
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, one.copyRO(), lone.copyRO())));
EMIT(CPOS(s,
MIR_Set.create(IA32_SET__B,
lone.copyRO(),
OPT_IA32ConditionOperand.NE()))); // lone = (val1 != val2) ? 1 : 0
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, res.copyRO()))); // res = (val1 <
// val2) ? -1 :0
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), lone.copyRO())));
EMIT(MIR_Unary.mutate(s, IA32_MOVSX__B, res.copyRO(), res.copyRO()));
}
/**
* Expansion of FP_ADD_ACC, FP_MUL_ACC, FP_SUB_ACC, and FP_DIV_ACC. Moves
* first value into fp0, accumulates second value into fp0 using op, moves fp0
* into result.
*
* @param s the instruction to expand
* @param op the floating point op to use
* @param result the result operand
* @param val1 the first operand
* @param val2 the second operand
*/
protected final void FP_MOV_OP_MOV(OPT_Instruction s, OPT_Operator op, OPT_Operand result, OPT_Operand val1,
OPT_Operand val2) {
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(0)), val1)));
EMIT(MIR_BinaryAcc.mutate(s, op, D(getFPR(0)), val2));
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, result, D(getFPR(0)))));
}
/**
* Expansion of FP_REM
*
* @param s the instruction to expand
* @param val1 the first operand
* @param val2 the second operand
*/
protected final void FP_REM(OPT_Instruction s, OPT_Operand val1, OPT_Operand val2) {
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(1)), val2)));
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(0)), val1)));
EMIT(MIR_BinaryAcc.mutate(s, IA32_FPREM, D(getFPR(0)), D(getFPR(1))));
}
/**
* Expansion for [DF]CMP[GL] compare to values and set result to -1, 0, 1 for <, =, >,
* respectively
*
* @param s the compare instruction
*/
protected final void threeValueFPCmp(OPT_Instruction s) {
// IMPORTANT: FCOMI only sets 3 of the 6 bits in EFLAGS, so
// we can't quite just translate the condition operand as if it
// were an integer compare.
// FCMOI sets ZF, PF, and CF as follows:
// Compare Results ZF PF CF
// left > right 0 0 0
// left < right 0 0 1
// left == right 1 0 0
// UNORDERED 1 1 1
OPT_RegisterOperand one = (OPT_RegisterOperand) Binary.getClearVal1(s);
OPT_RegisterOperand two = (OPT_RegisterOperand) Binary.getClearVal2(s);
OPT_RegisterOperand res = Binary.getClearResult(s);
OPT_RegisterOperand temp = burs.ir.regpool.makeTempInt();
OPT_Register FP0 = burs.ir.regpool.getPhysicalRegisterSet().getFPR(0);
if ((s.operator == DOUBLE_CMPL) || (s.operator == FLOAT_CMPL)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, IC(0))));
// Perform compare
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, new OPT_RegisterOperand(FP0, VM_TypeReference.Int), one)));
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, new OPT_RegisterOperand(FP0, VM_TypeReference.Int), two)));
// res = (value1 > value2) ? 1 : 0
// temp = ((value1 < value2) || unordered) ? -1 : 0
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, res, OPT_IA32ConditionOperand
.LGT())));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, temp.copyRO(), temp.copyRO())));
} else {
OPT_RegisterOperand temp2 = burs.ir.regpool.makeTempInt();
// Perform compare
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, new OPT_RegisterOperand(FP0, VM_TypeReference.Int), one)));
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, new OPT_RegisterOperand(FP0, VM_TypeReference.Int), two)));
// res = (value1 > value2) ? 1 : 0
// temp2 = (value1 unordered value2) ? 1 : 0
// temp = ((value1 unordered value2) ? 1 : 0) - 0 - CF
// (i.e. temp = (value1 < value2) ? -1 : 0)
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, OPT_IA32ConditionOperand
.PO())));
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, res, OPT_IA32ConditionOperand
.LGT())));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp2, temp.copyRO())));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, temp.copyRO(), IC(0))));
// Put result from temp2 in res
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), temp2.copyRO())));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), temp.copyRO())));
EMIT(MIR_Unary.mutate(s, IA32_MOVSX__B, res.copyRO(), res.copyRO()));
}
/**
* Expansion of BOOLEAN_CMP_INT
*
* @param s the instruction to copy position info from
* @param res the result operand
* @param val1 the first value
* @param val2 the second value
* @param cond the condition operand
*/
protected final void BOOLEAN_CMP_INT(OPT_Instruction s, OPT_RegisterOperand res, OPT_Operand val1, OPT_Operand val2,
OPT_ConditionOperand cond) {
EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, val1, val2)));
OPT_RegisterOperand temp = regpool.makeTemp(VM_TypeReference.Boolean);
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyD2U()));
}
/**
* Expansion of a special case of BOOLEAN_CMP_INT when the condition registers
* have already been set by the previous ALU op.
*
* @param s the instruction to copy position info from
* @param res the result operand
* @param cond the condition operand
*/
protected final void BOOLEAN_CMP_INT(OPT_Instruction s, OPT_RegisterOperand res, OPT_ConditionOperand cond) {
OPT_RegisterOperand temp = regpool.makeTemp(VM_TypeReference.Boolean);
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyD2U()));
}
/**
* Expansion of BOOLEAN_CMP_DOUBLE
*
* @param s the instruction to copy position info from
* @param res the result operand
* @param val1 the first value
* @param val2 the second value
* @param cond the condition operand
*/
protected final void BOOLEAN_CMP_DOUBLE(OPT_Instruction s, OPT_RegisterOperand res, OPT_ConditionOperand cond,
OPT_Operand val1, OPT_Operand val2) {
OPT_RegisterOperand temp = regpool.makeTemp(VM_TypeReference.Boolean);
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(0)), CondMove.getVal1(s))));
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, D(getFPR(0)), CondMove
.getVal2(s))));
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyD2U()));
}
/**
* Expansion of BOOLEAN_CMP_LONG
*
* @param s the instruction to copy position info from
* @param res the result operand
* @param val1 the first value
* @param val2 the second value
* @param cond the condition operand
*/
protected final void BOOLEAN_CMP_LONG(OPT_Instruction s, OPT_RegisterOperand res, OPT_Operand val1, OPT_Operand val2,
OPT_ConditionOperand cond) {
// Can we simplify to a shift?
if (cond.isLESS() && val2.isLongConstant() && val2.asLongConstant().value == 0 && val1.isRegister()) {
// Put the most significant bit of val1 into res
OPT_Register val1_reg = val1.asRegister().getRegister();
EMIT(MIR_Move.create(IA32_MOV, res.copyRO(), new OPT_RegisterOperand(val1_reg, VM_TypeReference.Int)));
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR, res, IC(31)));
} else if (cond.isGREATER_EQUAL() && val2.isLongConstant() && val2.asLongConstant().value == 0 && val1.isRegister()) {
// Put the most significant bit of val1 into res and invert
OPT_Register val1_reg = val1.asRegister().getRegister();
EMIT(MIR_Move.create(IA32_MOV, res.copyRO(), new OPT_RegisterOperand(val1_reg, VM_TypeReference.Int)));
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR, res, IC(31)));
EMIT(MIR_BinaryAcc.create(IA32_XOR, res.copyRO(), IC(1)));
} else {
// Long comparison is a subtraction:
// <, >= : easy to compute as SF !=/== OF
// >, <= : flipOperands and treat as a </>=
// ==/!= : do subtract then OR 2 32-bit quantities test for zero/non-zero
if (cond.isGREATER() || cond.isLESS_EQUAL()) {
OPT_Operand swap_temp;
cond.flipOperands();
swap_temp = val1;
val1 = val2;
val2 = swap_temp;
}
if (VM.VerifyAssertions) {
VM._assert(cond.isEQUAL() || cond.isNOT_EQUAL() || cond.isLESS() || cond.isGREATER_EQUAL());
}
OPT_RegisterOperand one = regpool.makeTempInt();
OPT_RegisterOperand lone = regpool.makeTempInt();
OPT_Operand two, ltwo;
if (val1 instanceof OPT_RegisterOperand) {
OPT_Register val1_reg = val1.asRegister().getRegister();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new OPT_RegisterOperand(val1_reg, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
lone,
new OPT_RegisterOperand(regpool.getSecondReg(val1_reg), VM_TypeReference.Int))));
} else {
OPT_LongConstantOperand tmp = (OPT_LongConstantOperand) val1;
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, IC(tmp.upper32()))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lone, IC(tmp.lower32()))));
}
if (val2 instanceof OPT_RegisterOperand) {
two = val2;
ltwo = L(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()));
} else {
OPT_LongConstantOperand tmp = (OPT_LongConstantOperand) val2;
two = IC(tmp.upper32());
ltwo = IC(tmp.lower32());
}
if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, lone.copyRO(), ltwo)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, one.copyRO(), lone.copyRO())));
} else {
EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, lone.copyRO(), ltwo)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
}
OPT_RegisterOperand temp = regpool.makeTemp(VM_TypeReference.Boolean);
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyRO()));
}
}
/**
* Generate a long compare and cmov
*
* @param s the instruction to copy position info from
* @param result the result of the conditional move
* @param val1 the first value
* @param val2 the second value
* @param cond the condition operand
* @param trueValue the value to move to result if cond is true
* @param falseValue the value to move to result if cond is not true
*/
protected final void LCMP_CMOV(OPT_Instruction s, OPT_RegisterOperand result, OPT_Operand val1, OPT_Operand val2,
OPT_ConditionOperand cond, OPT_Operand trueValue, OPT_Operand falseValue) {
// Long comparison is a subtraction:
// <, >= : easy to compute as SF !=/== OF
// >, <= : flipOperands and treat as a </>=
// ==/!= : do subtract then OR 2 32-bit quantities test for zero/non-zero
if (cond.isGREATER() || cond.isLESS_EQUAL()) {
OPT_Operand swap_temp;
cond.flipOperands();
swap_temp = val1;
val1 = val2;
val2 = swap_temp;
}
if (VM.VerifyAssertions) {
VM._assert(cond.isEQUAL() || cond.isNOT_EQUAL() || cond.isLESS() || cond.isGREATER_EQUAL());
}
OPT_RegisterOperand one = regpool.makeTempInt();
OPT_RegisterOperand lone = regpool.makeTempInt();
OPT_Operand two, ltwo;
if (val1 instanceof OPT_RegisterOperand) {
OPT_Register val1_reg = val1.asRegister().getRegister();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new OPT_RegisterOperand(val1_reg, VM_TypeReference.Int))));
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
lone,
new OPT_RegisterOperand(regpool.getSecondReg(val1_reg), VM_TypeReference.Int))));
} else {
OPT_LongConstantOperand tmp = (OPT_LongConstantOperand) val1;
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, IC(tmp.upper32()))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lone, IC(tmp.lower32()))));
}
if (val2 instanceof OPT_RegisterOperand) {
two = val2;
ltwo = L(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()));
} else {
OPT_LongConstantOperand tmp = (OPT_LongConstantOperand) val2;
two = IC(tmp.upper32());
ltwo = IC(tmp.lower32());
}
if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, lone.copyRO(), ltwo)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, one.copyRO(), lone.copyRO())));
} else {
EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, lone.copyRO(), ltwo)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
}
CMOV_MOV(s, result, cond, trueValue, falseValue);
}
/**
* Generate a compare and branch sequence. Used in the expansion of trees
* where INT_IFCMP is a root
*
* @param s the ifcmp instruction
* @param guardResult the guard result of the ifcmp
* @param val1 the first value operand
* @param val2 the second value operand
* @param cond the condition operand
*/
protected final void IFCMP(OPT_Instruction s, OPT_RegisterOperand guardResult, OPT_Operand val1, OPT_Operand val2,
OPT_ConditionOperand cond) {
if (VM.VerifyAssertions) {
// We only need make sure the guard information is correct when
// validating, the null check combining phase removes all guards
EMIT(CPOS(s, Move.create(GUARD_MOVE, guardResult, new OPT_TrueGuardOperand())));
}
EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, val1, val2)));
EMIT(MIR_CondBranch.mutate(s, IA32_JCC, COND(cond), IfCmp.getTarget(s), IfCmp.getBranchProfile(s)));
}
/**
* Generate an integer move portion of a conditional move.
*
* @param s the instruction to copy position info from
* @param result the result of the conditional move
* @param cond the condition operand
* @param trueValue the value to move to result if cond is true
* @param falseValue the value to move to result if cond is not true
*/
protected final void CMOV_MOV(OPT_Instruction s, OPT_RegisterOperand result, OPT_ConditionOperand cond,
OPT_Operand trueValue, OPT_Operand falseValue) {
if (result.similar(trueValue)) {
// in this case, only need a conditional move for the false branch.
EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result, asReg(s, IA32_MOV, falseValue), COND(cond.flipCode())));
} else if (result.similar(falseValue)) {
// in this case, only need a conditional move for the true branch.
EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result, asReg(s, IA32_MOV, trueValue), COND(cond)));
} else {
// need to handle both possible assignments. Unconditionally
// assign one value then conditionally assign the other.
if (falseValue.isRegister()) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result, trueValue)));
EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result.copyRO(), falseValue, COND(cond.flipCode())));
} else {
if (trueValue.isRegister()) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result, falseValue)));
EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result.copyRO(), trueValue, COND(cond)));
} else {
// Perform constant move without creating a register (costs
// 1 or 2 more instructions but saves a register)
int true_const = ((OPT_IntConstantOperand) trueValue).value;
int false_const = ((OPT_IntConstantOperand) falseValue).value;
// Generate values for consts trying to avoid zero extending the
// set__b result
// result = cond ? 1 : 0
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, result.copyRO(), COND(cond))));
if ((true_const - false_const) == 1) {
// result = (cond ? 1 : 0) + false_const
EMIT(CPOS(s, MIR_Unary.create(IA32_MOVZX__B, result.copyRO(), result.copyRO())));
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(false_const)));
} else if ((false_const - true_const) == 1) {
// result = (cond ? -1 : 0) + false_const
EMIT(CPOS(s, MIR_Unary.create(IA32_MOVZX__B, result.copyRO(), result.copyRO())));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(false_const)));
} else if (((false_const - true_const) > 0) && ((false_const - true_const) <= 0xFF)) {
// result = cond ? 0 : -1
// result = (cond ? 0 : -1) & (false_const - true__const)
// result = ((cond ? 0 : -1) & (false_const - true_const)) +
// true_const
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, result.copyRO(), IC(1))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(false_const - true_const))));
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(true_const)));
} else {
// result = cond ? -1 : 0
// result = (cond ? -1 : 0) & (true_const - false_const)
// result = ((cond ? -1 : 0) & (true_const - false_const)) +
// false_const
if (((true_const - false_const) > 0xFF) || ((true_const - false_const) < 0)) {
EMIT(CPOS(s, MIR_Unary.create(IA32_MOVZX__B, result.copyRO(), result.copyRO())));
}
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(true_const - false_const))));
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(false_const)));
}
}
}
}
}
/**
* Generate a floating point move portion of a conditional move.
*
* @param s the instruction to copy position info from
* @param result the result of the conditional move
* @param cond the condition operand
* @param trueValue the value to move to result if cond is true
* @param falseValue the value to move to result if cond is not true
*/
protected final void CMOV_FMOV(OPT_Instruction s, OPT_RegisterOperand result, OPT_ConditionOperand cond,
OPT_Operand trueValue, OPT_Operand falseValue) {
if (result.similar(trueValue)) {
// in this case, only need a conditional move for the false branch.
EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, result, asReg(s, IA32_FMOV, falseValue), COND(cond.flipCode())));
} else if (result.similar(falseValue)) {
// in this case, only need a conditional move for the true branch.
EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, result, asReg(s, IA32_FMOV, trueValue), COND(cond)));
} else {
// need to handle both possible assignments. Unconditionally
// assign one value then conditionally assign the other.
if (falseValue.isRegister()) {
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, result, trueValue)));
EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, result.copyRO(), falseValue, COND(cond.flipCode())));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, result, falseValue)));
EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, result.copyRO(), asReg(s, IA32_FMOV, trueValue), COND(cond)));
}
}
}
/**
* Expand a prologue by expanding out longs into pairs of ints
*/
protected final void PROLOGUE(OPT_Instruction s) {
int numFormals = Prologue.getNumberOfFormals(s);
int numLongs = 0;
for (int i = 0; i < numFormals; i++) {
if (Prologue.getFormal(s, i).getType().isLongType()) {
numLongs++;
}
}
if (numLongs != 0) {
OPT_Instruction s2 = Prologue.create(IR_PROLOGUE, numFormals + numLongs);
for (int sidx = 0, s2idx = 0; sidx < numFormals; sidx++) {
OPT_RegisterOperand sForm = Prologue.getFormal(s, sidx);
if (sForm.getType().isLongType()) {
sForm.setType(VM_TypeReference.Int);
Prologue.setFormal(s2, s2idx++, sForm);
OPT_Register r2 = regpool.getSecondReg(sForm.getRegister());
Prologue.setFormal(s2, s2idx++, new OPT_RegisterOperand(r2, VM_TypeReference.Int));
sForm.getRegister().clearType();
sForm.getRegister().setInteger();
r2.clearType();
r2.setInteger();
} else {
Prologue.setFormal(s2, s2idx++, sForm);
}
}
EMIT(s2);
} else {
EMIT(s);
}
}
/**
* Expansion of CALL. Expand longs registers into pairs of int registers.
*
* @param s the instruction to expand
* @param address the operand containing the target address
*/
protected final void CALL(OPT_Instruction s, OPT_Operand address) {
// Step 1: Find out how many parameters we're going to have.
int numParams = Call.getNumberOfParams(s);
int longParams = 0;
for (int pNum = 0; pNum < numParams; pNum++) {
if (Call.getParam(s, pNum).getType().isLongType()) {
longParams++;
}
}
// Step 2: Figure out what the result and result2 values will be.
OPT_RegisterOperand result = Call.getResult(s);
OPT_RegisterOperand result2 = null;
if (result != null && result.getType().isLongType()) {
result.setType(VM_TypeReference.Int);
result2 = new OPT_RegisterOperand(regpool.getSecondReg(result.getRegister()), VM_TypeReference.Int);
}
// Step 3: Mutate the Call to an MIR_Call.
// Note MIR_Call and Call have a different number of fixed
// arguments, so some amount of copying is required.
OPT_Operand[] params = new OPT_Operand[numParams];
for (int i = 0; i < numParams; i++) {
params[i] = Call.getParam(s, i);
}
MIR_Call.mutate(s, IA32_CALL, result, result2, address, Call.getMethod(s), numParams + longParams);
for (int paramIdx = 0, mirCallIdx = 0; paramIdx < numParams;) {
OPT_Operand param = params[paramIdx++];
if (param instanceof OPT_RegisterOperand) {
MIR_Call.setParam(s, mirCallIdx++, param);
OPT_RegisterOperand rparam = (OPT_RegisterOperand) param;
if (rparam.getType().isLongType()) {
MIR_Call.setParam(s, mirCallIdx++, L(regpool
.getSecondReg(rparam.getRegister())));
}
} else if (param instanceof OPT_LongConstantOperand) {
OPT_LongConstantOperand val = (OPT_LongConstantOperand) param;
MIR_Call.setParam(s, mirCallIdx++, IC(val.upper32()));
MIR_Call.setParam(s, mirCallIdx++, IC(val.lower32()));
} else {
MIR_Call.setParam(s, mirCallIdx++, param);
}
}
// emit the call instruction.
EMIT(s);
}
/**
* Expansion of SYSCALL. Expand longs registers into pairs of int registers.
*
* @param s the instruction to expand
* @param address the operand containing the target address
*/
protected final void SYSCALL(OPT_Instruction s, OPT_Operand address) {
burs.ir.setHasSysCall(true);
// Step 1: Find out how many parameters we're going to have.
int numParams = Call.getNumberOfParams(s);
int longParams = 0;
for (int pNum = 0; pNum < numParams; pNum++) {
if (Call.getParam(s, pNum).getType().isLongType()) {
longParams++;
}
}
// Step 2: Figure out what the result and result2 values will be.
OPT_RegisterOperand result = Call.getResult(s);
OPT_RegisterOperand result2 = null;
// NOTE: C callee returns longs little endian!
if (result != null && result.getType().isLongType()) {
result.setType(VM_TypeReference.Int);
result2 = result;
result = new OPT_RegisterOperand(regpool.getSecondReg(result.getRegister()), VM_TypeReference.Int);
}
// Step 3: Mutate the Call to an MIR_Call.
// Note MIR_Call and Call have a different number of fixed
// arguments, so some amount of copying is required.
OPT_Operand[] params = new OPT_Operand[numParams];
for (int i = 0; i < numParams; i++) {
params[i] = Call.getParam(s, i);
}
MIR_Call.mutate(s, IA32_SYSCALL, result, result2, address, Call
.getMethod(s), numParams + longParams);
for (int paramIdx = 0, mirCallIdx = 0; paramIdx < numParams;) {
OPT_Operand param = params[paramIdx++];
if (param instanceof OPT_RegisterOperand) {
// NOTE: longs passed little endian to C callee!
OPT_RegisterOperand rparam = (OPT_RegisterOperand) param;
if (rparam.getType().isLongType()) {
MIR_Call.setParam(s, mirCallIdx++, L(regpool
.getSecondReg(rparam.getRegister())));
}
MIR_Call.setParam(s, mirCallIdx++, param);
} else if (param instanceof OPT_LongConstantOperand) {
long value = ((OPT_LongConstantOperand) param).value;
int valueHigh = (int) (value >> 32);
int valueLow = (int) (value & 0xffffffff);
// NOTE: longs passed little endian to C callee!
MIR_Call.setParam(s, mirCallIdx++, IC(valueLow));
MIR_Call.setParam(s, mirCallIdx++, IC(valueHigh));
} else {
MIR_Call.setParam(s, mirCallIdx++, param);
}
}
// emit the call instruction.
EMIT(s);
}
/**
* Expansion of LOWTABLESWITCH.
*
* @param s the instruction to expand
*/
protected final void LOWTABLESWITCH(OPT_Instruction s) {
// (1) We're changing index from a U to a DU.
// Inject a fresh copy instruction to make sure we aren't
// going to get into trouble (if someone else was also using index).
OPT_RegisterOperand newIndex = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, newIndex, LowTableSwitch.getIndex(s))));
int number = LowTableSwitch.getNumberOfTargets(s);
OPT_Instruction s2 = CPOS(s, MIR_LowTableSwitch.create(MIR_LOWTABLESWITCH, newIndex.copyRO(), number * 2));
for (int i = 0; i < number; i++) {
MIR_LowTableSwitch.setTarget(s2, i, LowTableSwitch.getTarget(s, i));
MIR_LowTableSwitch.setBranchProfile(s2, i, LowTableSwitch
.getBranchProfile(s, i));
}
EMIT(s2);
}
/**
* Expansion of RESOLVE. Dynamic link point. Build up MIR instructions for
* Resolve.
*
* @param s the instruction to expand
*/
protected final void RESOLVE(OPT_Instruction s) {
OPT_Operand target = loadFromJTOC(VM_Entrypoints.optResolveMethod.getOffset(), DW);
EMIT(CPOS(s,
MIR_Call.mutate0(s,
CALL_SAVE_VOLATILE,
null,
null,
target,
OPT_MethodOperand.STATIC(VM_Entrypoints.optResolveMethod))));
}
/**
* 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(OPT_Instruction s, boolean longConstant) {
OPT_RegisterOperand gRes = TrapIf.getGuardResult(s);
OPT_RegisterOperand v1 = (OPT_RegisterOperand) TrapIf.getVal1(s);
OPT_ConstantOperand v2 = (OPT_ConstantOperand) TrapIf.getVal2(s);
OPT_ConditionOperand cond = TrapIf.getCond(s);
OPT_TrapCodeOperand tc = TrapIf.getTCode(s);
// A slightly ugly matter, but we need to deal with combining
// the two pieces of a long register from a LONG_ZERO_CHECK.
// A little awkward, but probably the easiest workaround...
if (longConstant) {
if (VM.VerifyAssertions) {
VM._assert((tc.getTrapCode() == VM_Runtime.TRAP_DIVIDE_BY_ZERO) &&
(((OPT_LongConstantOperand) v2).value == 0L));
}
OPT_RegisterOperand rr = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, rr, v1.copy())));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
rr.copy(),
new OPT_RegisterOperand(regpool.getSecondReg(v1.getRegister()), VM_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));
}
/**
* This routine expands an ATTEMPT instruction into an atomic
* compare exchange. The atomic compare and exchange will place at
* mo the value of newValue if the value of mo is oldValue. The
* result register is set to 0/1 depending on whether the valye was
* replaced or not.
*
* @param result the register operand that is set to 0/1 as a result of the
* attempt
* @param mo the address at which to attempt the exchange
* @param oldValue the old value at the address mo
* @param newValue the new value at the address mo
*/
protected final void ATTEMPT(OPT_RegisterOperand result, OPT_MemoryOperand mo, OPT_Operand oldValue,
OPT_Operand newValue) {
OPT_RegisterOperand temp = regpool.makeTempInt();
OPT_RegisterOperand temp2 = regpool.makeTemp(result);
EMIT(MIR_Move.create(IA32_MOV, temp, newValue));
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int), oldValue));
EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
mo,
temp.copyRO()));
EMIT(MIR_Set.create(IA32_SET__B, temp2, OPT_IA32ConditionOperand.EQ()));
// need to zero-extend the result of the set
EMIT(MIR_Unary.create(IA32_MOVZX__B, result, temp2.copy()));
}
/**
* This routine expands an ATTEMPT instruction into an atomic
* compare exchange. The atomic compare and exchange will place at
* mo the value of newValue if the value of mo is oldValue. The
* result register is set to 0/1 depending on whether the valye was
* replaced or not.
*
* @param result the register operand that is set to 0/1 as a result
* of the attempt
* @param mo the address at which to attempt the exchange
* @param oldValue the old value to check for at the address mo
* @param newValue the new value to place at the address mo
*/
protected final void ATTEMPT_LONG(OPT_RegisterOperand result,
OPT_MemoryOperand mo,
OPT_Operand oldValue,
OPT_Operand newValue) {
// Set up EDX:EAX with the old value
if (oldValue.isRegister()) {
OPT_Register oldValue_hval = oldValue.asRegister().getRegister();
OPT_Register oldValue_lval = regpool.getSecondReg(oldValue_hval);
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(oldValue_hval, VM_TypeReference.Int)));
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
new OPT_RegisterOperand(oldValue_lval, VM_TypeReference.Int)));
} else {
if (VM.VerifyAssertions) VM._assert(oldValue.isLongConstant());
OPT_LongConstantOperand val = oldValue.asLongConstant();
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
IC(val.upper32())));
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
IC(val.lower32())));
}
// Set up ECX:EBX with the new value
if (newValue.isRegister()) {
OPT_Register newValue_hval = newValue.asRegister().getRegister();
OPT_Register newValue_lval = regpool.getSecondReg(newValue_hval);
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getECX(), VM_TypeReference.Int),
new OPT_RegisterOperand(newValue_hval, VM_TypeReference.Int)));
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEBX(), VM_TypeReference.Int),
new OPT_RegisterOperand(newValue_lval, VM_TypeReference.Int)));
} else {
if (VM.VerifyAssertions) VM._assert(newValue.isLongConstant());
OPT_LongConstantOperand val = newValue.asLongConstant();
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getECX(), VM_TypeReference.Int),
IC(val.upper32())));
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEBX(), VM_TypeReference.Int),
IC(val.lower32())));
}
EMIT(MIR_CompareExchange8B.create(IA32_LOCK_CMPXCHG8B,
new OPT_RegisterOperand(getEDX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
mo,
new OPT_RegisterOperand(getECX(), VM_TypeReference.Int),
new OPT_RegisterOperand(getEBX(), VM_TypeReference.Int)));
OPT_RegisterOperand temp = regpool.makeTemp(result);
EMIT(MIR_Set.create(IA32_SET__B, temp, OPT_IA32ConditionOperand.EQ()));
// need to zero-extend the result of the set
EMIT(MIR_Unary.create(IA32_MOVZX__B, result, temp.copy()));
}
/**
* This routine expands the compound pattern IFCMP(ATTEMPT, ZERO) into an
* atomic compare/exchange followed by a branch on success/failure of the
* attempted atomic compare/exchange.
*
* @param mo the address at which to attempt the exchange
* @param oldValue the old value at the address mo
* @param newValue the new value at the address mo
* @param cond the condition to branch on
* @param target the branch target
* @param bp the branch profile information
*/
protected final void ATTEMPT_IFCMP(OPT_MemoryOperand mo, OPT_Operand oldValue, OPT_Operand newValue,
OPT_ConditionOperand cond, OPT_BranchOperand target, OPT_BranchProfileOperand bp) {
OPT_RegisterOperand temp = regpool.makeTempInt();
EMIT(MIR_Move.create(IA32_MOV, temp, newValue));
EMIT(MIR_Move.create(IA32_MOV, new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int), oldValue));
EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
new OPT_RegisterOperand(getEAX(), VM_TypeReference.Int),
mo,
temp.copyRO()));
EMIT(MIR_CondBranch.create(IA32_JCC, COND(cond), target, bp));
}
/*
* special case handling OSR instructions expand long type variables to two
* intergers
*/
void OSR(OPT_BURS burs, OPT_Instruction s) {
if (VM.VerifyAssertions) {
VM._assert(OsrPoint.conforms(s));
}
// 1. how many params
int numparam = OsrPoint.getNumberOfElements(s);
int numlong = 0;
for (int i = 0; i < numparam; i++) {
OPT_Operand param = OsrPoint.getElement(s, i);
if (param.getType().isLongType()) {
numlong++;
}
}
// 2. collect params
OPT_InlinedOsrTypeInfoOperand typeInfo = OsrPoint
.getClearInlinedTypeInfo(s);
if (VM.VerifyAssertions) {
if (typeInfo == null) {
VM.sysWriteln("OsrPoint " + s + " has a <null> type info:");
VM.sysWriteln(" position :" + s.bcIndex + "@" + s.position.method);
}
VM._assert(typeInfo != null);
}
OPT_Operand[] params = new OPT_Operand[numparam];
for (int i = 0; i < numparam; i++) {
params[i] = OsrPoint.getClearElement(s, i);
}
// set the number of valid params in osr type info, used
// in LinearScan
typeInfo.validOps = numparam;
// 3: only makes second half register of long being used
// creates room for long types.
burs.append(OsrPoint.mutate(s, s.operator(), typeInfo, numparam + numlong));
int pidx = numparam;
for (int i = 0; i < numparam; i++) {
OPT_Operand param = params[i];
OsrPoint.setElement(s, i, param);
if (param instanceof OPT_RegisterOperand) {
OPT_RegisterOperand rparam = (OPT_RegisterOperand) param;
// the second half is appended at the end
// OPT_LinearScan will update the map.
if (rparam.getType().isLongType()) {
OsrPoint.setElement(s, pidx++, L(burs.ir.regpool
.getSecondReg(rparam.getRegister())));
}
} else if (param instanceof OPT_LongConstantOperand) {
OPT_LongConstantOperand val = (OPT_LongConstantOperand) param;
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("caught a long const " + val);
}
OsrPoint.setElement(s, i, IC(val.upper32()));
OsrPoint.setElement(s, pidx++, IC(val.lower32()));
} else if (param instanceof OPT_IntConstantOperand) {
} else {
throw new OPT_OptimizingCompilerException("OPT_BURS_Helpers", "unexpected parameter type" + param);
}
}
if (pidx != (numparam + numlong)) {
VM.sysWriteln("pidx = " + pidx);
VM.sysWriteln("numparam = " + numparam);
VM.sysWriteln("numlong = " + numlong);
}
if (VM.VerifyAssertions) {
VM._assert(pidx == (numparam + numlong));
}
/*
* if (VM.TraceOnStackReplacement) { VM.sysWriteln("BURS rewrite OsrPoint
* "+s); VM.sysWriteln(" position "+s.bcIndex+"@"+s.position.method); }
*/
}
}