/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.lir2mir.ia32;
import static org.jikesrvm.compilers.opt.OptimizingCompilerException.UNREACHABLE;
import static org.jikesrvm.compilers.opt.OptimizingCompilerException.opt_assert;
import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_CMPL;
import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_CMPL;
import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE;
import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHL;
import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHR;
import static org.jikesrvm.compilers.opt.ir.Operators.LONG_USHR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CALL_SAVE_VOLATILE;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADC;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_AND;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDNPD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDNPS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDPD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDPS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_BT;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CALL;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CDQ;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMP;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPEQSD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPEQSS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLESD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLESS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLTSD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLTSS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CVTSS2SD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_DIV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCMOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCOMI;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCOMIP;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FFREE;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FILD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FIST;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLD1;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDL2E;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDL2T;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDLG2;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDLN2;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDPI;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDZ;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FPREM;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FSTP;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IDIV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IMUL1;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IMUL2;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_JCC;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_LEA;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_LOCK_CMPXCHG;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_LOCK_CMPXCHG8B;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_METHODSTART;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSXDQ;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSX__B;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVZX__B;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MUL;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_NEG;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_NOT;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_OR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ORPD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ORPS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_RCR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_RDTSC;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SAR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SBB;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SET__B;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHL;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SUB;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SYSCALL;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_TRAPIF;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XOR;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XORPD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XORPS;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.MIR_LOWTABLESWITCH;
import static org.jikesrvm.ia32.RegisterConstants.JTOC_REGISTER;
import static org.jikesrvm.util.Bits.fits;
import java.util.Enumeration;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.DefUse;
import org.jikesrvm.compilers.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.IR;
import org.jikesrvm.compilers.opt.ir.IfCmp;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.LowTableSwitch;
import org.jikesrvm.compilers.opt.ir.Move;
import org.jikesrvm.compilers.opt.ir.Nullary;
import org.jikesrvm.compilers.opt.ir.Operator;
import org.jikesrvm.compilers.opt.ir.OsrPoint;
import org.jikesrvm.compilers.opt.ir.Prologue;
import org.jikesrvm.compilers.opt.ir.Register;
import org.jikesrvm.compilers.opt.ir.TrapIf;
import org.jikesrvm.compilers.opt.ir.Unary;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_BinaryAcc;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Call;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Compare;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_CompareExchange;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_CompareExchange8B;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_CondBranch;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_CondMove;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_ConvertDW2QW;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Divide;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Lea;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_LowTableSwitch;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Move;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Multiply;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Nullary;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_RDTSC;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Set;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_TrapIf;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Unary;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_UnaryAcc;
import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand;
import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand;
import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
import org.jikesrvm.compilers.opt.ir.operand.ia32.BURSManagedFPROperand;
import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand;
import org.jikesrvm.compilers.opt.lir2mir.BURS;
import org.jikesrvm.compilers.opt.lir2mir.BURS_MemOp_Helpers;
import org.jikesrvm.runtime.Entrypoints;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.runtime.RuntimeEntrypoints;
import org.jikesrvm.runtime.Statics;
import org.vmmagic.unboxed.Offset;
/**
* Contains IA32-specific helper functions for BURS.
*/
public abstract class BURS_Helpers extends 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");
/** Mask to flip sign bits in XMM registers */
private static final Offset floatSignMask =
VM.BuildForSSE2Full ?
Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x8000000080000000L, 0x8000000080000000L)) :
Offset.zero();
/** Mask to flip sign bits in XMM registers */
private static final Offset doubleSignMask =
VM.BuildForSSE2Full ?
Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x8000000000000000L, 0x8000000000000000L)) :
Offset.zero();
/** Mask to abs an XMM registers */
private static final Offset floatAbsMask =
VM.BuildForSSE2Full ?
Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x7FFFFFFF7FFFFFFFL, 0x7FFFFFFF7FFFFFFFL)) :
Offset.zero();
/** Mask to abs an XMM registers */
private static final Offset doubleAbsMask =
VM.BuildForSSE2Full ?
Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x7FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL)) :
Offset.zero();
/**
* When emitting certain rules this holds the condition code state to be
* consumed by a parent rule
*/
private ConditionOperand cc;
public BURS_Helpers(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(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
if (VM.VerifyAssertions) opt_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()) {
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(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
if (VM.VerifyAssertions) opt_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
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(Operator operator, Instruction s, Operand result, Operand value) {
if (VM.VerifyAssertions) opt_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(Instruction s, RegisterOperand result, MemoryOperand mo) {
// A memory operand is: base + scaled index + displacement
if ((mo.index == null) && mo.disp.isZero()) {
if (VM.VerifyAssertions) opt_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) opt_assert(mo.scale == 0);
if (VM.VerifyAssertions) opt_assert(fits(mo.disp, 32));
// 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 ConditionOperand BIT_TEST(int x, ConditionOperand cond) {
if (VM.VerifyAssertions) opt_assert((x == 0) || (x == 1));
if (VM.VerifyAssertions) opt_assert(EQ_NE(cond));
if ((x == 1 && cond.isEQUAL()) ||
(x == 0 && cond.isNOT_EQUAL())) {
return ConditionOperand.LOWER();
} else {
return 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 Operand follow(Operand use) {
if (!use.isRegister()) {
return use;
} else {
RegisterOperand rop = use.asRegister();
Enumeration<RegisterOperand> defs = DefUse.defs(rop.getRegister());
if (!defs.hasMoreElements()) {
return use;
} else {
Operand def = defs.nextElement();
if (defs.hasMoreElements()) {
return def;
} else {
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(ConditionOperand c) {
if (VM.VerifyAssertions) {
opt_assert(cc == null);
}
cc = c;
}
/**
* Acquire remembered condition code in parent
*
* @return condition code
*/
protected final ConditionOperand consumeCOND() {
ConditionOperand ans = cc;
if (VM.VerifyAssertions) {
opt_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 static int LEA_SHIFT(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 static int LEA_SHIFT(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(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 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 static int is387_FPC(Instruction s, int trueCost) {
Operand val = Binary.getVal2(s);
if (val instanceof FloatConstantOperand) {
FloatConstantOperand fc = (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 {
DoubleConstantOperand dc = (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 Operator get387_FPC(Instruction s) {
Operand val = Binary.getVal2(s);
if (val instanceof FloatConstantOperand) {
FloatConstantOperand fc = (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 {
DoubleConstantOperand dc = (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 OptimizingCompilerException("BURS_Helpers", "unexpected 387 constant " + val);
}
/**
* Can the given condition for a compare be converted to a test?
*
* @param op a condition
* @return {@code true} if and only if the condition for the compare
* can be reduced to a test
*/
protected static boolean CMP_TO_TEST(ConditionOperand op) {
switch(op.value) {
case ConditionOperand.EQUAL:
case ConditionOperand.NOT_EQUAL:
case ConditionOperand.LESS:
case ConditionOperand.GREATER_EQUAL:
case ConditionOperand.GREATER:
case ConditionOperand.LESS_EQUAL:
return true;
default:
return false;
}
}
protected final IA32ConditionOperand COND(ConditionOperand op) {
return new IA32ConditionOperand(op);
}
// Get particular physical registers
protected final Register getEAX() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getEAX();
}
protected final Register getECX() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getECX();
}
protected final Register getEDX() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getEDX();
}
protected final Register getEBX() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getEBX();
}
protected final Register getESP() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getESP();
}
protected final Register getEBP() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getEBP();
}
protected final Register getESI() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getESI();
}
protected final Register getEDI() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getEDI();
}
protected final Register getFPR(int n) {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getFPR(n);
}
protected final Operand myFP0() {
return new BURSManagedFPROperand(0);
}
protected final Operand myFP1() {
return new BURSManagedFPROperand(1);
}
protected final Register getST0() {
return getIR().regpool.getPhysicalRegisterSet().asIA32().getST0();
}
/**
* Emits code to move the operand into a register operand if it
* isn't one already.
*
* @param movop the Operator that needs to be used for the move
* @param op the operand to move
* @param s instruction to get source position information
* @return a new operand if a move was inserted, the old operand
* otherwise
*/
private Operand asReg(Instruction s, Operator movop, Operand op) {
if (op.isRegister()) {
return op;
}
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 MemoryOperand setSize(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 Operand MO_CONV(byte size) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
return new StackLocationOperand(true, offset, size);
}
/**
* Creates a 64bit slot on the stack in memory for a conversion and
* stores the given long.
*
* @param op an operand representing a long
*/
protected final void STORE_LONG_FOR_CONV(Operand op) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
if (VM.BuildFor32Addr) {
if (op instanceof RegisterOperand) {
RegisterOperand hval = (RegisterOperand) op;
RegisterOperand lval = new RegisterOperand(regpool.getSecondReg(hval.getRegister()),
TypeReference.Int);
EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset + 4, DW), hval));
EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, DW), lval));
} else {
LongConstantOperand val = LC(op);
EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset + 4, DW), IC(val.upper32())));
EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, DW), IC(val.lower32())));
}
} else {
if (op instanceof RegisterOperand) {
RegisterOperand val = (RegisterOperand) op;
EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, QW), val));
} else {
LongConstantOperand val = LC(op);
EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, QW), val));
}
}
}
/**
* Create memory operand to load from a given jtoc offset
*
* @param ir the IR to use for getting a JTOC reg operand, if available
* @param offset location in JTOC
* @param size of value in JTOC
* @return created memory operand
*/
static MemoryOperand loadFromJTOC(IR ir, Offset offset, byte size) {
LocationOperand loc = new LocationOperand(offset);
Operand guard = TG();
if (JTOC_REGISTER == null) {
return MemoryOperand.D(Magic.getTocPointer().plus(offset), size, loc, guard);
} else {
return MemoryOperand.BD(ir.regpool.makeTocOp().asRegister(), 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(Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForCaughtException();
StackLocationOperand sl = new 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(Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForCaughtException();
StackLocationOperand sl = new StackLocationOperand(true, offset, DW);
Operand val = CacheOp.getClearRef(s);
if (val.isRegister()) {
EMIT(MIR_Move.mutate(s, IA32_MOV, sl, val));
} else if (val.isConstant()) {
RegisterOperand temp;
if (val.isIntConstant()) {
if (VM.VerifyAssertions) opt_assert(VM.BuildFor32Addr);
temp = regpool.makeTempInt();
} else if (val.isLongConstant()) {
if (VM.VerifyAssertions) opt_assert(VM.BuildFor64Addr);
temp = regpool.makeTempLong();
} else {
throw new OptimizingCompilerException("BURS_Helpers",
"unexpected operand type " + val + " in SET_EXCEPTION_OBJECT");
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val)));
val = temp.copyRO(); // for opt compiler var usage info?
EMIT(MIR_Move.mutate(s, IA32_MOV, sl, temp.copy()));
} else {
throw new OptimizingCompilerException("BURS_Helpers",
"unexpected operand type " + val + " in SET_EXCEPTION_OBJECT");
}
}
/**
* 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(Instruction s, RegisterOperand result,
Operand value, boolean signExtend) {
if (VM.BuildFor32Addr) {
Register hr = result.getRegister();
Register lr = regpool.getSecondReg(hr);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lr, TypeReference.Int), value)));
if (signExtend) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(hr, TypeReference.Int),
new RegisterOperand(lr, TypeReference.Int))));
EMIT(MIR_BinaryAcc.mutate(s,IA32_SAR,
new RegisterOperand(hr, TypeReference.Int),
IC(31)));
} else {
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(hr, TypeReference.Int),
IC(0)));
}
} else {
if (signExtend) {
if (result.isRegister()) {
EMIT(MIR_Unary.mutate(s, IA32_MOVSXDQ, result, value));
} else {
// MOVSX only accepts registers as target
RegisterOperand tempLong = regpool.makeTempLong();
EMIT(CPOS(s, MIR_Unary.create(IA32_MOVSXDQ, tempLong, value)));
EMIT(MIR_Move.mutate(s, IA32_MOV,
result,
tempLong.copy()));
}
} else {
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, value)));
RegisterOperand tempLong = regpool.makeTempLong();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, tempLong, temp.copy())));
EMIT(MIR_Move.mutate(s, IA32_MOV,
result,
tempLong.copy()));
}
}
}
/**
* Emits code to clear the upper 32 bits of a register on x64.
*
* @param s the instruction to use for positioning information
* @param rop the register to clear
*/
protected final void CLEAR_UPPER_32(Instruction s, RegisterOperand rop) {
if (VM.BuildFor64Addr) {
RegisterOperand regAsInt = rop.copy().asRegister();
regAsInt.setType(TypeReference.Int);
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, regAsInt, regAsInt.copy())));
} else {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
}
}
/**
* 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(Instruction s, RegisterOperand result, Operand value) {
MemoryOperand M;
// Step 1: Get value to be converted into myFP0
// and in 'strict' IEEE mode.
if (value instanceof 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 BURSManagedFPROperand) {
if (VM.VerifyAssertions) {
opt_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
Register one = regpool.getInteger();
Register isPositive = regpool.getInteger();
Register isNegative = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(one, TypeReference.Int), IC(1))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(isPositive, TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(isNegative, 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 RegisterOperand(isPositive, TypeReference.Int),
new RegisterOperand(one, TypeReference.Int),
IA32ConditionOperand.LLT())));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new RegisterOperand(isNegative, TypeReference.Int),
new RegisterOperand(one, TypeReference.Int),
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
Register addee = regpool.getInteger();
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 RegisterOperand(addee, TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(subtractee, TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new RegisterOperand(addee, TypeReference.Int),
new RegisterOperand(one, TypeReference.Int),
IA32ConditionOperand.LLT())));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
new RegisterOperand(subtractee, TypeReference.Int),
new RegisterOperand(one, TypeReference.Int),
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 RegisterOperand(addee, TypeReference.Int),
new RegisterOperand(isNegative, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
new RegisterOperand(subtractee, TypeReference.Int),
new RegisterOperand(isPositive, 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 RegisterOperand(addee, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, result.copy(), new RegisterOperand(subtractee, TypeReference.Int))));
// Compare myFP0 with (double)Integer.MAX_VALUE
M = loadFromJTOC(burs.ir, Entrypoints.maxintField.getOffset(), QW);
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
Register maxInt = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(maxInt, TypeReference.Int), IC(Integer.MAX_VALUE))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
result.copy(),
new RegisterOperand(maxInt, TypeReference.Int),
IA32ConditionOperand.LLT())));
// Compare myFP0 with (double)Integer.MIN_VALUE
M = MemoryOperand.D(Magic.getTocPointer().plus(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
Register minInt = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(minInt, TypeReference.Int), IC(Integer.MIN_VALUE))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
result.copy(),
new RegisterOperand(minInt, TypeReference.Int),
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
Register zero = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(zero, TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
result.copy(),
new RegisterOperand(zero, TypeReference.Int),
IA32ConditionOperand.PE())));
}
/**
* Emits code to move 64 bits from FPRs to GPRs
*
* @param s instruction to modify for the move
*/
protected final void FPR2GPR_64(Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, sl, Unary.getClearVal(s))));
RegisterOperand i1 = Unary.getClearResult(s);
RegisterOperand i2 = new RegisterOperand(regpool
.getSecondReg(i1.getRegister()), TypeReference.Int);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, i1, sl1)));
EMIT(MIR_Move.mutate(s, IA32_MOV, i2, sl2));
}
/**
* Emits code to move 64 bits from GPRs to FPRs.
*
* @param s instruction to modify for the move
*/
protected final void GPR2FPR_64(Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
Operand i1, i2;
Operand val = Unary.getClearVal(s);
if (val instanceof RegisterOperand) {
RegisterOperand rval = (RegisterOperand) val;
i1 = val;
i2 = new RegisterOperand(regpool.getSecondReg(rval.getRegister()), TypeReference.Int);
} else {
LongConstantOperand rhs = (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.
*
* @param o an operand
* @return correct move operator
*/
protected final Operator SSE2_MOVE(Operand o) {
return o.isFloat() ? IA32_MOVSS : IA32_MOVSD;
}
/**
* Returns the size based on the type of operand.
*
* @param o an operand
* @return size in bytes
*/
protected final byte SSE2_SIZE(Operand o) {
return o.isFloat() ? DW : QW;
}
/**
* Performs a long -> double/float conversion using x87 and
* marshalls back to XMMs.
*
* @param s instruction to modify for the conversion
*/
protected final void SSE2_X87_FROMLONG(Instruction s) {
Operand result = Unary.getClearResult(s);
STORE_LONG_FOR_CONV(Unary.getClearVal(s));
// conversion space allocated, contains the long to load.
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
StackLocationOperand sl = new StackLocationOperand(true, offset, SSE2_SIZE(result));
RegisterOperand st0 = new 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.
*
* @param s instruction to modify for the conversion
*/
protected final void SSE2_X87_REM(Instruction s) {
Operand result = Binary.getClearResult(s);
RegisterOperand st0 = new RegisterOperand(getST0(), result.getType());
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
StackLocationOperand sl = new StackLocationOperand(true, offset, SSE2_SIZE(result));
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), sl, Binary.getClearVal2(s))));
EMIT(CPOS(s, MIR_Move.create(IA32_FLD, st0, sl.copy())));
EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), sl.copy(), Binary.getClearVal1(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(CPOS(s, MIR_Nullary.create(IA32_FFREE, st0.copy())));
EMIT(MIR_Move.mutate(s, SSE2_MOVE(result), result, sl.copy()));
}
/**
* Emits code to move 64 bits from SSE2 FPRs to GPRs
*
* @param s instruction to modify for the move
*/
protected final void SSE2_FPR2GPR_64(Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
Operand val = Unary.getClearVal(s);
if (VM.BuildFor32Addr) {
StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
EMIT(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, val)));
RegisterOperand i1 = Unary.getClearResult(s);
RegisterOperand i2 = new RegisterOperand(regpool
.getSecondReg(i1.getRegister()), TypeReference.Int);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, i1, sl1)));
EMIT(MIR_Move.mutate(s, IA32_MOV, i2, sl2));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, val)));
EMIT(MIR_Move.mutate(s, IA32_MOV, Unary.getResult(s), sl.copy()));
}
}
/**
* Emits code to move 64 bits from GPRs to SSE2 FPRs
*
* @param s instruction to modify for the move
*/
protected final void SSE2_GPR2FPR_64(Instruction s) {
int offset = -burs.ir.stackManager.allocateSpaceForConversion();
StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
Operand val = Unary.getClearVal(s);
if (VM.BuildFor32Addr) {
StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
Operand i1, i2;
if (val instanceof RegisterOperand) {
RegisterOperand rval = (RegisterOperand) val;
i1 = val;
i2 = new RegisterOperand(regpool.getSecondReg(rval.getRegister()), TypeReference.Int);
} else {
LongConstantOperand rhs = (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));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl, val)));
EMIT(MIR_Move.mutate(s, IA32_MOVSD, Unary.getResult(s), sl.copy()));
}
}
/**
* Emits code to move 32 bits from FPRs to GPRs.
*
* @param s instruction to modify for the move
*/
protected final void SSE2_FPR2GPR_32(Instruction s) {
EMIT(MIR_Move.mutate(s, IA32_MOVD, Unary.getResult(s), Unary.getVal(s)));
// int offset = -burs.ir.stackManager.allocateSpaceForConversion();
// StackLocationOperand sl = new 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()));
}
/**
* Emits code to move 32 bits from GPRs to FPRs.
*
* @param s instruction to modify for the move
*/
protected final void SSE2_GPR2FPR_32(Instruction s) {
EMIT(MIR_Move.mutate(s, IA32_MOVD, Unary.getResult(s), Unary.getVal(s)));
// int offset = -burs.ir.stackManager.allocateSpaceForConversion();
// StackLocationOperand sl = new 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.
*
* @param operator the operator
* @param s the instruction in question
* @param result the instruction's result operand
* @param val1 the instruction's first value operand
* @param val2 the instruction's second value operand
*/
protected void SSE2_COP(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
if (VM.VerifyAssertions) opt_assert(result.isRegister());
// Swap operands to reduce chance of generating a move or to normalize
// constants into val2
if (val2.similar(result)) {
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.
*
* @param operator the operator
* @param s the instruction in question
* @param result the instruction's result operand
* @param val1 the instruction's first value operand
* @param val2 the instruction's second value operand
*/
protected void SSE2_NCOP(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
if (VM.VerifyAssertions) opt_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
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.
*
* @param single {@code true} if 32 bit value (float), {@code false} for 64 bit (double)
* @param s the instruction in question
* @param result the instruction's result operand
* @param value the instruction's value operand
*/
protected final void SSE2_NEG(boolean single, Instruction s, Operand result, Operand value) {
if (VM.VerifyAssertions) opt_assert(result.isRegister());
if (!result.similar(value)) {
EMIT(CPOS(s, MIR_Move.create(single ? IA32_MOVSS : IA32_MOVSD, result.copy(), value)));
}
Offset signMaskOffset = single ? floatSignMask : doubleSignMask;
EMIT(MIR_BinaryAcc.mutate(s, single ? IA32_XORPS : IA32_XORPD, result,
loadFromJTOC(burs.ir, signMaskOffset, PARAGRAPH)));
}
/**
* Expansion of SSE2 conversions double <-> float
*
* @param op the operator
* @param s the instruction in question
* @param result the instruction's result operand
* @param value the instruction's value operand
*/
protected final void SSE2_CONV(Operator op, Instruction s, Operand result, Operand value) {
if (VM.VerifyAssertions) opt_assert(result.isRegister());
EMIT(MIR_Unary.mutate(s, op, result, value));
}
/**
* Expansion of SSE2 comparison operations
*
* @param op the operator
* @param s the instruction in question
* @param val1 the instruction's first value operand
* @param val2 the instruction's second value operand
*/
protected final void SSE2_IFCMP(Operator op, Instruction s, Operand val1, Operand val2) {
EMIT(CPOS(s, MIR_Compare.create(op, val1, val2)));
EMIT(s); // ComplexLIR2MIRExpansion will handle rest of the work.
}
protected static Operator SSE2_CMP_OP(ConditionOperand cond, boolean single) {
switch(cond.value) {
case ConditionOperand.CMPL_EQUAL:
return single ? IA32_CMPEQSS : IA32_CMPEQSD;
case ConditionOperand.CMPG_LESS:
return single ? IA32_CMPLTSS : IA32_CMPLTSD;
case ConditionOperand.CMPG_LESS_EQUAL:
return single ? IA32_CMPLESS : IA32_CMPLESD;
default:
return null;
}
}
protected final void SSE2_FCMP_FCMOV(Instruction s, RegisterOperand result, Operand lhsCmp, Operand rhsCmp,
ConditionOperand cond, Operand trueValue, Operand falseValue) {
final boolean singleResult = result.isFloat();
final boolean singleCmp = lhsCmp.isFloat();
// TODO: support for the MAXSS/MAXSD instructions taking care of NaN cases
// find cmpOperator flipping code or operands as necessary
Operator cmpOperator = SSE2_CMP_OP(cond, singleCmp);
boolean needFlipOperands = false;
boolean needFlipCode = false;
if (cmpOperator == null) {
needFlipOperands = !needFlipOperands;
cmpOperator = SSE2_CMP_OP(cond.flipOperands(), singleCmp);
if (cmpOperator == null) {
needFlipCode = !needFlipCode;
cmpOperator = SSE2_CMP_OP(cond.flipCode(), singleCmp);
if (cmpOperator == null) {
needFlipOperands = !needFlipOperands;
cmpOperator = SSE2_CMP_OP(cond.flipOperands(), singleCmp);
if (VM.VerifyAssertions) opt_assert(cmpOperator != null);
}
}
}
if (needFlipOperands) {
Operand temp = lhsCmp;
lhsCmp = rhsCmp;
rhsCmp = temp;
}
if (needFlipCode) {
Operand temp = falseValue;
falseValue = trueValue;
trueValue = temp;
}
// place true value in a temporary register to be used for generation of result
RegisterOperand temp = regpool.makeTemp(result);
EMIT(CPOS(s, MIR_Move.create(singleResult ? IA32_MOVSS : IA32_MOVSD, temp, trueValue)));
// do compare ensuring size is >= size of result
if (!singleResult && singleCmp) {
RegisterOperand temp2 = regpool.makeTemp(result);
EMIT(CPOS(s, MIR_Unary.create(IA32_CVTSS2SD, temp2, rhsCmp)));
EMIT(CPOS(s, MIR_Unary.create(IA32_CVTSS2SD, result.copyRO(), lhsCmp)));
rhsCmp = temp2;
cmpOperator = SSE2_CMP_OP(cond, false);
} else {
if (!result.similar(lhsCmp)) {
EMIT(CPOS(s, MIR_Move.create(singleResult ? IA32_MOVSS : IA32_MOVSD, result.copyRO(), lhsCmp)));
}
}
EMIT(MIR_BinaryAcc.mutate(s, cmpOperator, result, rhsCmp));
// result contains all 1s or 0s, use masks and OR to perform conditional move
EMIT(CPOS(s, MIR_BinaryAcc.create(singleResult ? IA32_ANDPS : IA32_ANDPD, temp.copyRO(), result.copyRO())));
EMIT(CPOS(s, MIR_BinaryAcc.create(singleResult ? IA32_ANDNPS : IA32_ANDNPD, result.copyRO(), falseValue)));
EMIT(CPOS(s, MIR_BinaryAcc.create(singleResult ? IA32_ORPS : IA32_ORPD, result.copyRO(), temp.copyRO())));
}
protected static boolean IS_MATERIALIZE_ZERO(Instruction s) {
Operand val = Binary.getVal2(s); // float or double value
return (val.isFloatConstant() && Float.floatToRawIntBits(val.asFloatConstant().value) == 0) ||
(val.isDoubleConstant() && Double.doubleToRawLongBits(val.asDoubleConstant().value) == 0L);
}
protected static boolean SIMILAR_REGISTERS(Operand... ops) {
Operand last = null;
for (Operand op : ops) {
if (!op.isRegister() || (last != null && !op.similar(last))) {
return false;
}
last = op;
}
return true;
}
protected static boolean SSE2_IS_GT_OR_GE(ConditionOperand cond) {
switch(cond.value) {
case ConditionOperand.CMPG_GREATER:
case ConditionOperand.CMPG_GREATER_EQUAL:
case ConditionOperand.CMPL_GREATER:
case ConditionOperand.CMPL_GREATER_EQUAL:
return true;
}
return false;
}
protected static boolean SSE2_IS_LT_OR_LE(ConditionOperand cond) {
switch(cond.value) {
case ConditionOperand.CMPG_LESS:
case ConditionOperand.CMPG_LESS_EQUAL:
case ConditionOperand.CMPL_LESS:
case ConditionOperand.CMPL_LESS_EQUAL:
return true;
}
return false;
}
protected final void SSE2_ABS(boolean single, Instruction s, Operand result, Operand value) {
if (VM.VerifyAssertions) opt_assert(result.isRegister());
if (!result.similar(value)) {
EMIT(CPOS(s, MIR_Move.create(single ? IA32_MOVSS : IA32_MOVSD, result.copy(), value)));
}
Offset absMaskOffset = single ? floatAbsMask : doubleAbsMask;
EMIT(MIR_BinaryAcc.mutate(s, single ? IA32_ANDPS : IA32_ANDPD, result,
loadFromJTOC(burs.ir, absMaskOffset, PARAGRAPH)));
}
/**
* Expansion of SSE2 floating point constant loads
*
* @param s the instruction to mutate
*/
protected final void SSE2_FPCONSTANT(Instruction s) {
RegisterOperand res = Binary.getResult(s);
Operand val = Binary.getVal2(s); // float or double value
if (val.isFloatConstant() && Float.floatToRawIntBits(val.asFloatConstant().value) == 0) {
EMIT(MIR_BinaryAcc.mutate(s, IA32_XORPS, res, res.copyRO()));
} else if (val.isDoubleConstant() && Double.doubleToRawLongBits(val.asDoubleConstant().value) == 0L) {
EMIT(MIR_BinaryAcc.mutate(s, IA32_XORPD, res, res.copyRO()));
} else {
EMIT(MIR_Move.mutate(s, SSE2_MOVE(res), res, MO_MC(s)));
}
}
/**
* Expansion of INT_DIV, SIGNED_DIV_64_32, UNSIGNED_DIV_64_32 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 {@code true} for division,
* {@code false} for reminder
* @param signed {@code true} for signed,
* {@code false} for unsigned
*/
protected final void INT_DIVIDES(Instruction s, RegisterOperand result, Operand val1, Operand val2,
boolean isDiv, boolean signed) {
if (val1.isIntConstant()) {
int value = val1.asIntConstant().value;
if (value < 0) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int), IC(-1))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), val1)));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int), IC(0))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), val1)));
}
} else if (val1.isLongConstant()) {
int upper32 = val1.asLongConstant().upper32();
int lower32 = val1.asLongConstant().lower32();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int), IC(upper32))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), IC(lower32))));
} else if (val1.getType().isLongType()) {
if (VM.BuildFor32Addr) {
Register upperReg = ((RegisterOperand) val1).getRegister();
Register lowerReg = regpool.getSecondReg(upperReg);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(upperReg, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(lowerReg, TypeReference.Int))));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEDX(), TypeReference.Int),
val1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
val1)));
EMIT(CPOS(s, MIR_Move.create(IA32_SHR,
new RegisterOperand(getEDX(), TypeReference.Int),
LC(32))));
}
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), val1)));
EMIT(CPOS(s, MIR_ConvertDW2QW.create(IA32_CDQ,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
}
if (val2.isIntConstant()) {
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2)));
val2 = temp.copyRO();
}
EMIT(MIR_Divide.mutate(s,
signed ? IA32_IDIV : IA32_DIV,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
val2,
GuardedBinary.getGuard(s)));
if (isDiv) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEAX(), TypeReference.Int))));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEDX(), TypeReference.Int))));
}
}
/**
* Creates the MIR instruction given by the operators from the Binary LIR operands
* @param operator1 the 1st MIR operator
* @param operator2 the 2nd MIR operator
* @param s the instruction being replaced
* @param result the destination register/memory
* @param value1 the first operand
* @param value2 the second operand
* @param commutative is the operation commutative?
*/
protected final void EMIT_LongBinary(Operator operator1, Operator operator2,
Instruction s, Operand result,
Operand value1, Operand value2,
boolean commutative) {
// Save moves by swapping operands for commutative operations
if (commutative && value2.similar(result)) {
Operand temp = value1;
value1 = value2;
value2 = temp;
}
// commutative combinations are:
// reg, reg, reg
// reg, reg, mem
// reg, reg, constant
// reg, mem, constant
// mem, mem, reg - where the 2 mems are identical
// mem, mem, constant - where the 2 mems are identical
// non-commutative combinations are also:
// reg, constant, reg
// reg, constant, mem
// mem, constant, mem
// Break apart result
// Get into accumulate form
Operand lhs, lowlhs;
boolean needsMove = !value1.similar(result);
if (result.isRegister()) {
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = regpool.getSecondReg(lhsReg);
lowlhs = new RegisterOperand(lowlhsReg, TypeReference.Int);
lhs = new RegisterOperand(lhsReg, TypeReference.Int);
} else {
// Memory operand
if (VM.VerifyAssertions) opt_assert(result.isMemory());
lowlhs = setSize(result.asMemory(), DW);
lhs = lowlhs.copy();
lhs.asMemory().disp = lhs.asMemory().disp.plus(4);
}
// Clobbering can occur when a move is needed and result and value2 have the
// same type (e.g. when both result and value2 use the same register after
// register allocation).
boolean computeOnTemp = needsMove && result.similar(value2);
RegisterOperand temp1 = null;
RegisterOperand temp2 = null;
if (needsMove && !computeOnTemp) {
Operand rhs1, lowrhs1;
if (value1.isRegister()) {
Register rhs1Reg = value1.asRegister().getRegister();
Register lowrhs1Reg = regpool.getSecondReg(rhs1Reg);
lowrhs1 = new RegisterOperand(lowrhs1Reg, TypeReference.Int);
rhs1 = new RegisterOperand(rhs1Reg, TypeReference.Int);
} else if (value1.isMemory()) {
lowrhs1 = setSize(value1.asMemory(),DW);
rhs1 = lowrhs1.copy();
rhs1.asMemory().disp = rhs1.asMemory().disp.plus(4);
} else {
// Long constant operand
if (VM.VerifyAssertions) opt_assert(value1.isLongConstant());
rhs1 = IC(value1.asLongConstant().upper32());
lowrhs1 = IC(value1.asLongConstant().lower32());
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lowlhs.copy(), lowrhs1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lhs.copy(), rhs1)));
} else if (needsMove && computeOnTemp) {
// Clobbering can't occur for commutative operations due to canonical forms
if (VM.VerifyAssertions && computeOnTemp) opt_assert(!commutative);
// In order to prevent clobbering, the calculation will be done on temp
// registers and the result will be moved back to the proper result register
// later. Register allocation and subsequent optimizations will clean up
// any unneeded moves.
Operand rhs1, lowrhs1;
temp1 = regpool.makeTempInt();
temp2 = regpool.makeTempInt();
// Move value1 into temp
if (value1.isRegister()) {
Register rhs1Reg = value1.asRegister().getRegister();
Register lowrhs1Reg = regpool.getSecondReg(rhs1Reg);
lowrhs1 = new RegisterOperand(lowrhs1Reg, TypeReference.Int);
rhs1 = new RegisterOperand(rhs1Reg, TypeReference.Int);
} else if (value1.isMemory()) {
if (VM.VerifyAssertions) opt_assert(VM.NOT_REACHED);
lowrhs1 = setSize(value1.asMemory(),DW);
rhs1 = lowrhs1.copy();
rhs1.asMemory().disp = rhs1.asMemory().disp.plus(4);
} else {
rhs1 = IC(value1.asLongConstant().upper32());
lowrhs1 = IC(value1.asLongConstant().lower32());
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp1, lowrhs1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp2, rhs1)));
lowlhs = temp1.copy();
lhs = temp2.copy();
}
// Break apart RHS 2
Operand rhs2, lowrhs2;
if (value2.isRegister()) {
Register rhsReg2 = value2.asRegister().getRegister();
Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
rhs2 = new RegisterOperand(rhsReg2, TypeReference.Int);
lowrhs2 = new RegisterOperand(lowrhsReg2, TypeReference.Int);
} else if (value2.isLongConstant()) {
rhs2 = IC(value2.asLongConstant().upper32());
lowrhs2 = IC(value2.asLongConstant().lower32());
} else {
// Memory operand
lowrhs2 = setSize(value2.asMemory(),DW);
rhs2 = lowrhs2.copy();
rhs2.asMemory().disp = rhs2.asMemory().disp.plus(4);
}
// Peep hole optimizations
if ((operator1 == IA32_ADD) &&
lowrhs2.isIntConstant() &&
(lowrhs2.asIntConstant().value == 0)
) {
// operation has no effect
operator1 = null;
operator2 = IA32_ADD;
} else if ((operator1 == IA32_SUB) &&
lowrhs2.isIntConstant() &&
(lowrhs2.asIntConstant().value == 0)
) {
// operation has no effect
operator1 = null;
operator2 = IA32_SUB;
} else if (operator1 == IA32_OR) {
if (lowrhs2.isIntConstant()) {
if (lowrhs2.asIntConstant().value == 0) {
// operation has no effect
operator1 = null;
} else if (lowrhs2.asIntConstant().value == -1) {
// move 0
operator1 = IA32_MOV;
}
}
if (rhs2.isIntConstant()) {
if (rhs2.asIntConstant().value == 0) {
// operation has no effect
operator2 = null;
} else if (rhs2.asIntConstant().value == -1) {
// move -1
operator2 = IA32_MOV;
}
}
} else if (operator1 == IA32_AND) {
if (lowrhs2.isIntConstant()) {
if (lowrhs2.asIntConstant().value == -1) {
// operation has no effect
operator1 = null;
} else if (lowrhs2.asIntConstant().value == 0) {
// move 0
operator1 = IA32_MOV;
}
}
if (rhs2.isIntConstant()) {
if (rhs2.asIntConstant().value == -1) {
// operation has no effect
operator2 = null;
} else if (rhs2.asIntConstant().value == 0) {
// move 0
operator2 = IA32_MOV;
}
}
} else if (operator1 == IA32_XOR) {
if (lowrhs2.isIntConstant()) {
if (lowrhs2.asIntConstant().value == 0) {
// operation has no effect
operator1 = null;
} else if (lowrhs2.asIntConstant().value == -1) {
operator1 = IA32_NOT;
}
}
if (rhs2.isIntConstant()) {
if (rhs2.asIntConstant().value == 0) {
// operation has no effect
operator2 = null;
} else if (rhs2.asIntConstant().value == -1) {
operator2 = IA32_NOT;
}
}
}
// End of peephole optimizations
if (operator1 == null) {
// no operation
} else if (operator1 == IA32_MOV) {
EMIT(CPOS(s, MIR_Move.create(operator1,
lowlhs,
lowrhs2)));
} else if (operator1 == IA32_NOT) {
EMIT(CPOS(s, MIR_UnaryAcc.create(operator1,
lowlhs)));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(operator1,
lowlhs,
lowrhs2)));
}
if (operator2 == null) {
// no operation
} else if (operator2 == IA32_MOV) {
EMIT(CPOS(s, MIR_Move.create(operator2,
lhs,
rhs2)));
} else if (operator2 == IA32_NOT) {
EMIT(CPOS(s, MIR_UnaryAcc.create(operator2,
lhs)));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(operator2,
lhs,
rhs2)));
}
// Move results from temporaries to original result registers
if (computeOnTemp) {
if (result.isRegister()) {
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = regpool.getSecondReg(lhsReg);
lowlhs = new RegisterOperand(lowlhsReg, TypeReference.Int);
lhs = new RegisterOperand(lhsReg, TypeReference.Int);
} else {
// Memory operand
if (VM.VerifyAssertions) opt_assert(result.isMemory());
lowlhs = setSize(result.copy().asMemory(), DW);
lhs = lowlhs.copy();
lhs.asMemory().disp = lhs.asMemory().disp.plus(4);
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lowlhs, temp1.copy())));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lhs, temp2.copy())));
}
}
/**
* 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(Instruction s, RegisterOperand result,
Operand value1, Operand value2) {
if (value2.isRegister()) {
// Leave for complex LIR2MIR expansion as the most efficient form requires
// a branch
if (VM.VerifyAssertions) opt_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()) {
Operand temp = value1;
value1 = value2;
value2 = temp;
}
if (VM.VerifyAssertions) opt_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))
Register lhsReg = result.getRegister();
Register lowlhsReg = regpool.getSecondReg(lhsReg);
LongConstantOperand rhs2 = (LongConstantOperand) value2;
Register rhsReg1 = value1.asRegister().getRegister(); // a
Register lowrhsReg1 = regpool.getSecondReg(rhsReg1); // b
int high2 = rhs2.upper32(); // c
int low2 = rhs2.lower32(); // d
// We only have to handle those cases that Simplifier wouldn't get.
// 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) opt_assert(lhsReg != lowrhsReg1);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new RegisterOperand(lhsReg, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowlhsReg, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(getEDX(), 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
Register tmp = regpool.getInteger();
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new RegisterOperand(lowlhsReg, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(tmp, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(getEDX(), 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
Register tmp = regpool.getInteger();
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(tmp, TypeReference.Int))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new RegisterOperand(lowlhsReg, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(tmp, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowlhsReg, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(getEDX(), 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
Register tmp = regpool.getInteger();
if (lowlhsReg != lowrhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(tmp, TypeReference.Int),
IC(1))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(tmp, TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
new RegisterOperand(lowlhsReg, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(tmp, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
if (lhsReg != rhsReg1) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(tmp, TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_Move.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(tmp, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(low2))));
Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
new RegisterOperand(tmp, TypeReference.Int),
IC(high2))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(tmp, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
IC(low2))));
EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(getEDX(), TypeReference.Int))));
}
}
}
}
/**
* Expansion of LONG_MULs whose operands are ints
*
* @param s the instruction to expand
* @param result the result operand
* @param value1 the first operand
* @param value2 the second operand
* @param signed signed or unsigned multiplication?
*/
protected final void INT_TO_LONG_MUL(Instruction s, RegisterOperand result,
Operand value1, Operand value2, boolean signed) {
// Canonicalize with any constant on LHS that is placed in EAX
if (value2.isConstant()) {
Operand temp = value1;
value1 = value2;
value2 = temp;
}
// place LHS value into EAX
if (value1.isRegister()) {
RegisterOperand value1RO = value1.asRegister();
RegisterOperand lhsRO;
if (value1.getType().isLongType()) {
Register lhsReg = value1RO.getRegister();
Register lowlhsReg = regpool.getSecondReg(lhsReg);
lhsRO = new RegisterOperand(lowlhsReg, TypeReference.Int);
} else {
if (VM.VerifyAssertions) VM._assert(value1.getType().isIntType());
lhsRO = value1RO.copyRO();
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
lhsRO)));
} else {
if (VM.VerifyAssertions) VM._assert(value1.isConstant());
int lhsVal;
if (value1.isIntConstant()) {
lhsVal = value1.asIntConstant().value;
} else {
if (VM.VerifyAssertions) VM._assert(value1.isLongConstant());
lhsVal = value1.asLongConstant().lower32();
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(getEAX(), TypeReference.Int),
IC(lhsVal))));
}
// Multiply by low-half of RHS
if (VM.VerifyAssertions) VM._assert(value2.isRegister());
RegisterOperand value2RO = value2.asRegister();
Register rhsReg = value2RO.getRegister();
Register lowrhsReg;
if (rhsReg.isLong()) {
lowrhsReg = regpool.getSecondReg(rhsReg);
} else {
if (VM.VerifyAssertions) VM._assert(rhsReg.isInteger());
lowrhsReg = rhsReg;
}
EMIT(MIR_Multiply.mutate(s, signed ? IA32_IMUL1 : IA32_MUL,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(lowrhsReg, TypeReference.Int)));
// Move result into correct registers
Register resultReg = result.getRegister();
Register lowresultReg = regpool.getSecondReg(resultReg);
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowresultReg, TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(resultReg, TypeReference.Int),
new RegisterOperand(getEDX(), TypeReference.Int))));
}
/**
* Expansion of LONG_DIV and LONG_REM
*
* @param s the instruction to expand
* @param result the result operand
* @param val1 the first operand
* @param val2 the second operand
* @param isDiv {@code true} for div, {@code false} for rem
* @param signed {@code true} for signed division,
* {@code false} for unsigned
*/
protected final void LONG_DIVIDES(Instruction s, RegisterOperand result, Operand val1, Operand val2,
boolean isDiv, boolean signed) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Long), val1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Long), val1.copy())));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SAR, new RegisterOperand(getEDX(), TypeReference.Long), LC(0x3f))));
if (val2.isLongConstant() || val2.isIntConstant()) {
RegisterOperand temp = regpool.makeTempLong();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2)));
val2 = temp.copyRO();
}
EMIT(MIR_Divide.mutate(s,
signed ? IA32_IDIV : IA32_DIV,
new RegisterOperand(getEDX(), TypeReference.Long),
new RegisterOperand(getEAX(), TypeReference.Long),
val2,
GuardedBinary.getGuard(s)));
if (isDiv) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEAX(), TypeReference.Long))));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEDX(), TypeReference.Long))));
}
}
/**
* Creates the MIR instruction for LONG_NEG or LONG_NOT
* @param s the instruction being replaced
* @param result the destination register/memory
* @param value1 the operand
* @param negOrNot true for neg
*/
protected final void EMIT_LongUnary(Instruction s, Operand result,
Operand value1, boolean negOrNot) {
// Break apart result
// Get into accumulate form
Operand lhs, lowlhs;
boolean needsMove = !value1.similar(result);
if (result.isRegister()) {
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = regpool.getSecondReg(lhsReg);
lowlhs = new RegisterOperand(lowlhsReg, TypeReference.Int);
lhs = new RegisterOperand(lhsReg, TypeReference.Int);
} else {
// Memory operand
if (VM.VerifyAssertions) opt_assert(result.isMemory());
lowlhs = setSize(result.asMemory(),DW);
lhs = lowlhs.copy();
lhs.asMemory().disp = lhs.asMemory().disp.plus(4);
}
if (needsMove) {
Operand rhs1, lowrhs1;
if (value1.isRegister()) {
Register rhs1Reg = value1.asRegister().getRegister();
Register lowrhs1Reg = regpool.getSecondReg(rhs1Reg);
lowrhs1 = new RegisterOperand(lowrhs1Reg, TypeReference.Int);
rhs1 = new RegisterOperand(rhs1Reg, TypeReference.Int);
} else {
// Memory operand
if (VM.VerifyAssertions) opt_assert(value1.isMemory());
lowrhs1 = setSize(value1.asMemory(),DW);
rhs1 = lowrhs1.copy();
rhs1.asMemory().disp = rhs1.asMemory().disp.plus(4);
}
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lowlhs.copy(), lowrhs1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lhs.copy(), rhs1)));
}
if (negOrNot) {
// Perform negation
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, lowlhs)));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT, lhs)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, lhs.copy(), IC(-1))));
} else {
// Perform not
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT, lowlhs)));
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT, lhs)));
}
}
/**
* 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(Instruction s, Operand result,
Operand val1, 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;
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
Register rhsReg1 = val1.asRegister().getRegister();
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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_ADD,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowlhsReg, TypeReference.Int))));
EMIT(MIR_BinaryAcc.mutate(s,
IA32_ADC,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lhsReg, TypeReference.Int)));
} else if (shift == 2) {
// bits to shift in: tmp = lowrhsReg >> 30
Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(tmp, TypeReference.Int),
IC(30))));
// compute top half: lhsReg = (rhsReg1 << 2) + tmp
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lhsReg, TypeReference.Int),
MemoryOperand.BIS(new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int),
(byte)2, (byte)4, null, null))));
// compute bottom half: lowlhsReg = lowlhsReg << 2
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new MemoryOperand(null, // base
new RegisterOperand(lowrhsReg1, 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
Register tmp = regpool.getInteger();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(tmp, TypeReference.Int),
IC(29))));
// compute top half: lhsReg = (rhsReg1 << 3) + tmp
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lhsReg, TypeReference.Int),
MemoryOperand.BIS(new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int),
(byte)3, (byte)4, null, null))));
// compute bottom half: lowlhsReg = lowlhsReg << 3
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new MemoryOperand(null, // base
new RegisterOperand(lowrhsReg1, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
// bits to shift in: tmp = lowrhsReg >>> (32 - shift)
Register tmp = regpool.getInteger();
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(tmp, TypeReference.Int),
IC(32 - shift))));
// compute top half: lhsReg = (lhsReg1 << shift) | tmp
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(shift))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_OR,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(tmp, TypeReference.Int))));
// compute bottom half: lowlhsReg = lowlhsReg << shift
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHL,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(shift)));
} else if (shift == 32) {
// lhsReg = lowrhsReg1
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0)));
} else if (shift == 33) {
// lhsReg = lowrhsReg1 << 1
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lhsReg, TypeReference.Int),
new MemoryOperand(null, // base
new RegisterOperand(lowrhsReg1, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0)));
} else if (shift == 34) {
// lhsReg = lowrhsReg1 << 2
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lhsReg, TypeReference.Int),
new MemoryOperand(null, // base
new RegisterOperand(lowrhsReg1, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0)));
} else if (shift == 35) {
// lhsReg = lowrhsReg1 << 3
EMIT(CPOS(s,
MIR_Lea.create(IA32_LEA,
new RegisterOperand(lhsReg, TypeReference.Int),
new MemoryOperand(null, // base
new RegisterOperand(lowrhsReg1, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0)));
} else {
if ((maskWith3f) || (shift < 64)) {
// lhsReg = lowrhsReg1 << ((shift - 32) & 0x1f)
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new RegisterOperand(lhsReg, TypeReference.Int),
IC((shift - 32) & 0x1F))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0)));
} else {
// lhsReg = 0
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(0))));
// lowlhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0)));
}
}
} else {
throw new OptimizingCompilerException("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(Instruction s, Operand result,
Operand val1, 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;
}
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
Register rhsReg1 = val1.asRegister().getRegister();
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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
// lhsReg = lhsReg >> 1
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(1))));
// lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(1)));
} else if (shift < 32) {
// bits to shift in: tmp = rhsReg << (32 - shift)
// TODO: use of LEA for SHL
Register tmp = regpool.getInteger();
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new RegisterOperand(tmp, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(shift))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_OR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(tmp, TypeReference.Int))));
// compute top half: lhsReg = lhsReg >> shift
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SAR,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(shift)));
} else if (shift == 32) {
// lowlhsReg = rhsReg1
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int)));
// lhsReg = rhsReg1 >> 31
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new RegisterOperand(lhsReg, 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 RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(31))));
// lowlhsReg = lhsReg
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lhsReg, TypeReference.Int)));
} else {
// lhsReg = rhsReg1 >> 31
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(31))));
// lowlhsReg = rhsReg1 >> shift
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int)));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SAR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC((shift - 32) & 0x3F))));
}
}
} else {
throw new OptimizingCompilerException("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(Instruction s, Operand result,
Operand val1, 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;
}
Register lhsReg = result.asRegister().getRegister();
Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
Register rhsReg1 = val1.asRegister().getRegister();
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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
} else if (shift == 1) {
if (!result.similar(val1)) {
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
// lhsReg = lhsReg >>> 1
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(1))));
// lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(1)));
} else if (shift < 32) {
// bits to shift in: tmp = rhsReg << (32 - shift)
// TODO: use LEA for SHL operator
Register tmp = regpool.getInteger();
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(tmp, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHL,
new RegisterOperand(tmp, 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 RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(lowrhsReg1, TypeReference.Int))));
}
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(shift))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_OR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(tmp, TypeReference.Int))));
// compute top half: lhsReg = lhsReg >>> shift
if (!result.similar(val1)) {
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
}
EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(shift)));
} else if (shift == 32) {
// lowlhsReg = rhsReg1
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int)));
// lhsReg = 0
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(0))));
} else {
if (maskWith3f || (shift < 64)) {
// lowlhsReg = rhsReg1 >>> (shift & 0x1F)
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
new RegisterOperand(rhsReg1, TypeReference.Int))));
EMIT(CPOS(s,
MIR_BinaryAcc.create(IA32_SHR,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(shift & 0x1F))));
} else {
// lowlhsReg = 0
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
new RegisterOperand(lowlhsReg, TypeReference.Int),
IC(0))));
}
// lhsReg = 0
EMIT(MIR_Move.mutate(s, IA32_MOV,
new RegisterOperand(lhsReg, TypeReference.Int),
IC(0)));
}
} else {
throw new OptimizingCompilerException("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(Instruction s,
RegisterOperand result) {
if (VM.BuildFor32Addr) {
Register highReg = result.getRegister();
Register lowReg = regpool.getSecondReg(highReg);
EMIT(CPOS(s, MIR_RDTSC.create(IA32_RDTSC,
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(getEDX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(lowReg, TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(highReg, TypeReference.Int),
new RegisterOperand(getEDX(), TypeReference.Int))));
} else {
Register res = result.getRegister();
EMIT(CPOS(s, MIR_RDTSC.create(IA32_RDTSC,
new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(getEDX(), TypeReference.Int))));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
new RegisterOperand(res, TypeReference.Long),
new RegisterOperand(getEDX(), TypeReference.Long))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SHL,
new RegisterOperand(getEDX(), TypeReference.Long),
LC(32))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
new RegisterOperand(res, TypeReference.Long),
new RegisterOperand(getEAX(), TypeReference.Long))));
}
}
/**
* 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(Instruction s, RegisterOperand res, Operand val1, Operand val2) {
if (VM.BuildFor32Addr) {
RegisterOperand one = regpool.makeTempInt();
RegisterOperand lone = regpool.makeTempInt();
Operand two, ltwo;
if (val1 instanceof RegisterOperand) {
Register val1_reg = val1.asRegister().getRegister();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new RegisterOperand(val1_reg, TypeReference.Int))));
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
lone,
new RegisterOperand(regpool.getSecondReg(val1_reg), TypeReference.Int))));
} else {
LongConstantOperand tmp = (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 RegisterOperand) {
two = val2;
ltwo = L(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()));
} else {
LongConstantOperand tmp = (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, 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(),
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()));
} else {
RegisterOperand one = regpool.makeTempLong();
RegisterOperand two = regpool.makeTempLong();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, val1)));
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, two, val2)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, one, two)));
EMIT(CPOS(s,
MIR_Set.create(IA32_SET__B,
res,
IA32ConditionOperand.NE())));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SAR, one.copyRO(), LC(64))));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), one.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(Instruction s, Operator op, Operand result, Operand val1,
Operand val2) {
if (VM.BuildForSSE2) {
UNREACHABLE();
} else {
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(Instruction s, Operand val1, 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(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
RegisterOperand one = (RegisterOperand) Binary.getClearVal1(s);
RegisterOperand two = (RegisterOperand) Binary.getClearVal2(s);
RegisterOperand res = Binary.getClearResult(s);
RegisterOperand temp = burs.ir.regpool.makeTempInt();
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 RegisterOperand(FP0, TypeReference.Int), one)));
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, new RegisterOperand(FP0, TypeReference.Int), two)));
// res = (value1 > value2) ? 1 : 0
// temp = ((value1 < value2) || unordered) ? -1 : 0
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, res, IA32ConditionOperand.LGT())));
EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res.copyRO(), res.copyRO()));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, temp.copyRO(), temp.copyRO())));
} else {
RegisterOperand temp2 = burs.ir.regpool.makeTempInt();
// Perform compare
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, new RegisterOperand(FP0, TypeReference.Int), one)));
EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, new RegisterOperand(FP0, 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, IA32ConditionOperand
.PO())));
EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, res, 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()));
}
/**
* @param cond a condition operand
* @return whether the given condition operand need its operands flipping as its
* non-commutative
*/
private boolean getCMP_needsSwap(ConditionOperand cond) {
switch (cond.value) {
case ConditionOperand.BORROW_FROM_RSUB:
case ConditionOperand.NO_BORROW_FROM_RSUB:
case ConditionOperand.OVERFLOW_FROM_RSUB:
case ConditionOperand.NO_OVERFLOW_FROM_RSUB:
case ConditionOperand.RBIT_TEST:
case ConditionOperand.NO_RBIT_TEST:
return true;
default:
return false;
}
}
/**
* Gives the MIR condition operator appropriate for the given condition
* @param s the comparison instruction
* @param cond the condition
* @param val1 first operand for the compare
* @param val2 second operand for the compare
*/
protected void EMIT_Compare(Instruction s, ConditionOperand cond,
Operand val1, Operand val2) {
// Swap operands for non-commutative operators
if (getCMP_needsSwap(cond)) {
Operand temp = val1;
val2 = val1;
val1 = temp;
}
switch (cond.value) {
case ConditionOperand.CARRY_FROM_ADD:
case ConditionOperand.NO_CARRY_FROM_ADD:
case ConditionOperand.OVERFLOW_FROM_ADD:
case ConditionOperand.NO_OVERFLOW_FROM_ADD: {
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1.copy())));
EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, temp.copyRO(), val2));
break;
}
case ConditionOperand.BIT_TEST:
case ConditionOperand.NO_BIT_TEST:
case ConditionOperand.RBIT_TEST:
case ConditionOperand.NO_RBIT_TEST:
if (val2 instanceof MemoryOperand) {
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2.copy())));
val2 = temp;
}
EMIT(MIR_Compare.mutate(s, IA32_BT, val1.copy(), val2.copy()));
break;
case ConditionOperand.OVERFLOW_FROM_MUL:
case ConditionOperand.NO_OVERFLOW_FROM_MUL: {
RegisterOperand temp = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1.copy())));
EMIT(MIR_BinaryAcc.mutate(s, IA32_IMUL2, temp.copyRO(), val2));
break;
}
default:
EMIT(MIR_Compare.mutate(s, IA32_CMP, val1.copy(), val2.copy()));
break;
}
}
/**
* 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(Instruction s, RegisterOperand res, Operand val1, Operand val2,
ConditionOperand cond) {
EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, val1, val2)));
RegisterOperand temp = regpool.makeTemp(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(Instruction s, RegisterOperand res, ConditionOperand cond) {
RegisterOperand temp = regpool.makeTemp(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(Instruction s, RegisterOperand res, ConditionOperand cond,
Operand val1, Operand val2) {
RegisterOperand temp = regpool.makeTemp(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(Instruction s, RegisterOperand res, Operand val1, Operand val2,
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
Register val1_reg = val1.asRegister().getRegister();
EMIT(MIR_Move.create(IA32_MOV, res.copyRO(), new RegisterOperand(val1_reg, 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
Register val1_reg = val1.asRegister().getRegister();
EMIT(MIR_Move.create(IA32_MOV, res.copyRO(), new RegisterOperand(val1_reg, 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()) {
Operand swap_temp;
cond.flipOperands();
swap_temp = val1;
val1 = val2;
val2 = swap_temp;
}
if (VM.VerifyAssertions) {
opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL() || cond.isLESS() || cond.isGREATER_EQUAL());
}
RegisterOperand one = regpool.makeTempInt();
RegisterOperand lone = regpool.makeTempInt();
Operand two, ltwo;
if (val1 instanceof RegisterOperand) {
Register val1_reg = val1.asRegister().getRegister();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new RegisterOperand(val1_reg, TypeReference.Int))));
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
lone,
new RegisterOperand(regpool.getSecondReg(val1_reg), TypeReference.Int))));
} else {
LongConstantOperand tmp = (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 RegisterOperand) {
two = val2;
((RegisterOperand)two).setType(TypeReference.Int);
ltwo = new RegisterOperand(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()), TypeReference.Int);
} else {
LongConstantOperand tmp = (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)));
}
RegisterOperand temp = regpool.makeTemp(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(Instruction s, RegisterOperand result, Operand val1, Operand val2,
ConditionOperand cond, Operand trueValue, 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()) {
Operand swap_temp;
cond.flipOperands();
swap_temp = val1;
val1 = val2;
val2 = swap_temp;
}
if (VM.VerifyAssertions) {
opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL() || cond.isLESS() || cond.isGREATER_EQUAL());
}
RegisterOperand one = regpool.makeTempInt();
RegisterOperand lone = regpool.makeTempInt();
Operand two, ltwo;
if (val1 instanceof RegisterOperand) {
Register val1_reg = val1.asRegister().getRegister();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new RegisterOperand(val1_reg, TypeReference.Int))));
EMIT(CPOS(s,
MIR_Move.create(IA32_MOV,
lone,
new RegisterOperand(regpool.getSecondReg(val1_reg), TypeReference.Int))));
} else {
LongConstantOperand tmp = (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 RegisterOperand) {
two = val2;
((RegisterOperand)two).setType(TypeReference.Int);
ltwo = new RegisterOperand(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()), TypeReference.Int);
} else {
LongConstantOperand tmp = (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(Instruction s, RegisterOperand guardResult, Operand val1, Operand val2,
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 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(Instruction s, RegisterOperand result, ConditionOperand cond,
Operand trueValue, 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 = ((IntConstantOperand) trueValue).value;
int false_const = ((IntConstantOperand) falseValue).value;
if (cond.isLOWER()) {
// Comparison sets carry flag so use to avoid setb, movzx
// result = cond ? -1 : 0
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB, result, result.copyRO())));
if (true_const - false_const != -1) {
if (true_const - false_const == 1) {
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(true_const - false_const))));
}
}
if (false_const != 0) {
EMIT(MIR_BinaryAcc.create(IA32_ADD, result.copyRO(), IC(false_const)));
}
} else if (cond.isHIGHER_EQUAL()) {
// Comparison sets carry flag so use to avoid setb, movzx
// result = cond ? 0 : -1
EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB, result, result.copyRO())));
if (false_const - true_const != -1) {
if (false_const - true_const == 1) {
EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
} else {
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(false_const - true_const))));
}
}
if (true_const != 0) {
EMIT(MIR_BinaryAcc.create(IA32_ADD, result, IC(true_const)));
}
} else {
// 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(Instruction s, RegisterOperand result, ConditionOperand cond,
Operand trueValue, Operand falseValue) {
RegisterOperand FP0 = new RegisterOperand(burs.ir.regpool.getPhysicalRegisterSet().getFPR(0), result.getType());
// 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, FP0, trueValue)));
EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, FP0.copyRO(), falseValue, COND(cond.flipCode())));
} else {
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, FP0, falseValue)));
EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, FP0.copyRO(), asReg(s, IA32_FMOV, trueValue), COND(cond)));
}
EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, result.copyRO(), FP0.copyRO())));
}
/**
* Expand a prologue by expanding out longs into pairs of ints
*
* @param s the prologue instruction
*/
protected final void PROLOGUE(Instruction s) {
if (VM.BuildFor32Addr) {
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) {
Instruction s2 = createNewPrologueInst(s, numFormals + numLongs);
for (int sidx = 0, s2idx = 0; sidx < numFormals; sidx++) {
RegisterOperand sForm = Prologue.getClearFormal(s, sidx);
if (sForm.getType().isLongType()) {
sForm.setType(TypeReference.Int);
Prologue.setFormal(s2, s2idx++, sForm);
Register r2 = regpool.getSecondReg(sForm.getRegister());
Prologue.setFormal(s2, s2idx++, new RegisterOperand(r2, TypeReference.Int));
sForm.getRegister().clearType();
sForm.getRegister().setInteger();
r2.clearType();
r2.setInteger();
} else {
Prologue.setFormal(s2, s2idx++, sForm);
}
}
EMIT(s2);
} else {
EMIT(s);
}
} 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(Instruction s, Operand address) {
if (VM.BuildFor32Addr) {
// 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.
RegisterOperand result = Call.getResult(s);
RegisterOperand result2 = null;
if (result != null && result.getType().isLongType()) {
result.setType(TypeReference.Int);
result2 = new RegisterOperand(regpool.getSecondReg(result.getRegister()), 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.
Operand[] params = new 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;) {
Operand param = params[paramIdx++];
if (param instanceof RegisterOperand) {
RegisterOperand rparam = (RegisterOperand) param;
MIR_Call.setParam(s, mirCallIdx++, rparam);
if (rparam.getType().isLongType()) {
rparam.setType(TypeReference.Int);
MIR_Call.setParam(s, mirCallIdx - 1, rparam);
MIR_Call.setParam(s, mirCallIdx++,
new RegisterOperand(regpool.getSecondReg(rparam.getRegister()), TypeReference.Int));
}
} else if (param instanceof LongConstantOperand) {
LongConstantOperand val = (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);
}
}
} else {
MIR_Call.mutate(s, IA32_CALL, Call.getResult(s), null,
address, Call.getMethod(s), Call.getNumberOfParams(s));
}
// 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(Instruction s, Operand address) {
burs.ir.setHasSysCall(true);
if (VM.BuildFor32Addr) {
// 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.
RegisterOperand result = Call.getResult(s);
RegisterOperand result2 = null;
// NOTE: C callee returns longs little endian!
if (result != null && result.getType().isLongType()) {
result.setType(TypeReference.Int);
result2 = result;
result = new RegisterOperand(regpool.getSecondReg(result.getRegister()), 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.
Operand[] params = new 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;) {
Operand param = params[paramIdx++];
if (param instanceof RegisterOperand) {
// NOTE: longs passed little endian to C callee!
RegisterOperand rparam = (RegisterOperand) param;
if (rparam.getType().isLongType()) {
rparam.setType(TypeReference.Int);
MIR_Call.setParam(s, mirCallIdx++,
new RegisterOperand(regpool.getSecondReg(rparam.getRegister()), TypeReference.Int));
}
MIR_Call.setParam(s, mirCallIdx++, param);
} else if (param instanceof LongConstantOperand) {
long value = ((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);
}
}
} else {
MIR_Call.mutate(s, IA32_SYSCALL, Call.getResult(s), null,
address, Call.getMethod(s), Call.getNumberOfParams(s));
}
// emit the call instruction.
EMIT(s);
}
/**
* Expansion of LOWTABLESWITCH.
*
* @param s the instruction to expand
*/
protected final void LOWTABLESWITCH(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).
RegisterOperand newIndex = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, newIndex, LowTableSwitch.getClearIndex(s))));
RegisterOperand methodStart = regpool.makeTemp(TypeReference.Address);
EMIT(CPOS(s, MIR_Nullary.create(IA32_METHODSTART, methodStart)));
int number = LowTableSwitch.getNumberOfTargets(s);
Instruction s2 = CPOS(s, MIR_LowTableSwitch.create(MIR_LOWTABLESWITCH, newIndex.copyRO(), methodStart.copyD2U(), number * 2));
for (int i = 0; i < number; i++) {
MIR_LowTableSwitch.setTarget(s2, i, LowTableSwitch.getClearTarget(s, i));
MIR_LowTableSwitch.setBranchProfile(s2, i, LowTableSwitch
.getClearBranchProfile(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(Instruction s) {
Operand target = loadFromJTOC(burs.ir, Entrypoints.optResolveMethod.getOffset(), VM.BuildFor32Addr ? DW : QW);
EMIT(CPOS(s,
MIR_Call.mutate0(s,
CALL_SAVE_VOLATILE,
null,
null,
target,
MethodOperand.STATIC(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(Instruction s, boolean longConstant) {
RegisterOperand gRes = TrapIf.getGuardResult(s);
RegisterOperand v1 = (RegisterOperand) TrapIf.getVal1(s);
ConstantOperand v2 = (ConstantOperand) TrapIf.getVal2(s);
ConditionOperand cond = TrapIf.getCond(s);
TrapCodeOperand tc = TrapIf.getTCode(s);
// A 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 (VM.BuildFor32Addr && longConstant) {
if (VM.VerifyAssertions) {
opt_assert((tc.getTrapCode() == RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO) &&
(((LongConstantOperand) v2).value == 0L));
}
RegisterOperand vr = v1.copyRO();
vr.setType(TypeReference.Int);
RegisterOperand rr = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, rr, vr)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
rr.copy(),
new RegisterOperand(regpool.getSecondReg(v1.getRegister()), TypeReference.Int))));
v1 = rr.copyD2U();
v2 = IC(0);
}
// emit the trap instruction
EMIT(MIR_TrapIf.mutate(s, IA32_TRAPIF, gRes, v1, v2, COND(cond), tc));
}
/**
* This routine expands an ATTEMPT_INT 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_INT(RegisterOperand result, MemoryOperand mo, Operand oldValue,
Operand newValue) {
RegisterOperand temp = regpool.makeTempInt();
RegisterOperand temp2 = regpool.makeTemp(result);
EMIT(MIR_Move.create(IA32_MOV, temp, newValue));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), oldValue));
EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
new RegisterOperand(getEAX(), TypeReference.Int),
mo,
temp.copyRO()));
EMIT(MIR_Set.create(IA32_SET__B, temp2, 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(RegisterOperand result,
MemoryOperand mo,
Operand oldValue,
Operand newValue) {
if (VM.BuildFor32Addr) {
// Set up EDX:EAX with the old value
if (oldValue.isRegister()) {
Register oldValue_hval = oldValue.asRegister().getRegister();
Register oldValue_lval = regpool.getSecondReg(oldValue_hval);
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(oldValue_hval, TypeReference.Int)));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int),
new RegisterOperand(oldValue_lval, TypeReference.Int)));
} else {
if (VM.VerifyAssertions) opt_assert(oldValue.isLongConstant());
LongConstantOperand val = oldValue.asLongConstant();
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int),
IC(val.upper32())));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int),
IC(val.lower32())));
}
// Set up ECX:EBX with the new value
if (newValue.isRegister()) {
Register newValue_hval = newValue.asRegister().getRegister();
Register newValue_lval = regpool.getSecondReg(newValue_hval);
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getECX(), TypeReference.Int),
new RegisterOperand(newValue_hval, TypeReference.Int)));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEBX(), TypeReference.Int),
new RegisterOperand(newValue_lval, TypeReference.Int)));
} else {
if (VM.VerifyAssertions) opt_assert(newValue.isLongConstant());
LongConstantOperand val = newValue.asLongConstant();
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getECX(), TypeReference.Int),
IC(val.upper32())));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEBX(), TypeReference.Int),
IC(val.lower32())));
}
EMIT(MIR_CompareExchange8B.create(IA32_LOCK_CMPXCHG8B,
new RegisterOperand(getEDX(), TypeReference.Int),
new RegisterOperand(getEAX(), TypeReference.Int),
mo,
new RegisterOperand(getECX(), TypeReference.Int),
new RegisterOperand(getEBX(), TypeReference.Int)));
RegisterOperand temp = regpool.makeTemp(result);
EMIT(MIR_Set.create(IA32_SET__B, temp, IA32ConditionOperand.EQ()));
// need to zero-extend the result of the set
EMIT(MIR_Unary.create(IA32_MOVZX__B, result, temp.copy()));
} else {
RegisterOperand temp = regpool.makeTempLong();
RegisterOperand temp2 = regpool.makeTemp(result);
EMIT(MIR_Move.create(IA32_MOV, temp, newValue));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Long), oldValue));
EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
new RegisterOperand(getEAX(), TypeReference.Long),
mo,
temp.copyRO()));
EMIT(MIR_Set.create(IA32_SET__B, temp2, IA32ConditionOperand.EQ()));
// need to zero-extend the result of the set
EMIT(MIR_Unary.create(IA32_MOVZX__B, result, temp2.copy()));
}
}
/**
* This routine expands the compound pattern IFCMP(ATTEMPT_INT, 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_INT_IFCMP(MemoryOperand mo, Operand oldValue, Operand newValue,
ConditionOperand cond, BranchOperand target, BranchProfileOperand bp) {
RegisterOperand temp = regpool.makeTempInt();
EMIT(MIR_Move.create(IA32_MOV, temp, newValue.copy()));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), oldValue.copy()));
EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
new RegisterOperand(getEAX(), TypeReference.Int),
mo,
temp.copyRO()));
EMIT(MIR_CondBranch.create(IA32_JCC, COND(cond), target.copy().asBranch(), (BranchProfileOperand) bp.copy()));
}
/**
* This routine expands the compound pattern IFCMP(ATTEMPT_LONG, 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_LONG_IFCMP(MemoryOperand mo, Operand oldValue, Operand newValue,
ConditionOperand cond, BranchOperand target, BranchProfileOperand bp) {
if (VM.VerifyAssertions) opt_assert(VM.BuildFor64Addr, "Expansion of ifcmp of attempt_long NYI for 32-bit addressing!");
RegisterOperand temp = regpool.makeTempLong();
EMIT(MIR_Move.create(IA32_MOV, temp, newValue.copy()));
EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Long), oldValue.copy()));
EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
new RegisterOperand(getEAX(), TypeReference.Long),
mo,
temp.copyRO()));
EMIT(MIR_CondBranch.create(IA32_JCC, COND(cond), target.copy().asBranch(), (BranchProfileOperand) bp.copy()));
}
/**
* special case handling OSR instructions expand long type variables to two
* integers
* @param burs the burs instance
* @param s an OSRPoint instruction
*/
protected void OSR(BURS burs, Instruction s) {
if (VM.VerifyAssertions) {
opt_assert(OsrPoint.conforms(s));
}
// Check type info first because this needs to be done
// for both 32-bit and 64-bit cases.
InlinedOsrTypeInfoOperand typeInfo;
if (VM.BuildFor32Addr) {
// Clearing type info is ok, because instruction will be mutated and the
// info will be reinserted
typeInfo = OsrPoint.getClearInlinedTypeInfo(s);
} else {
// Instruction won't be changed so info needs to be left in
typeInfo = OsrPoint.getInlinedTypeInfo(s);
}
if (VM.VerifyAssertions) {
if (typeInfo == null) {
VM.sysWriteln("OsrPoint " + s + " has a <null> type info:");
VM.sysWriteln(" position :" + s.getBytecodeIndex() + "@" + s.position().method);
}
opt_assert(typeInfo != null);
}
int numparam = OsrPoint.getNumberOfElements(s);
if (VM.BuildFor32Addr) {
// 1. how many params
int numlong = 0;
for (int i = 0; i < numparam; i++) {
Operand param = OsrPoint.getElement(s, i);
if (param.getType().isLongType()) {
numlong++;
}
}
// 2. collect params
Operand[] params = new 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++) {
Operand param = params[i];
OsrPoint.setElement(s, i, param);
if (param instanceof RegisterOperand) {
RegisterOperand rparam = (RegisterOperand) param;
// the second half is appended at the end
// LinearScan will update the map.
if (rparam.getType().isLongType()) {
OsrPoint.setElement(s, pidx++, L(burs.ir.regpool
.getSecondReg(rparam.getRegister())));
}
} else if (param instanceof LongConstantOperand) {
LongConstantOperand val = (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 IntConstantOperand) {
} else {
throw new OptimizingCompilerException("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) {
opt_assert(pidx == (numparam + numlong));
}
} else {
// set the number of valid params in osr type info, used
// in LinearScan
typeInfo.validOps = numparam;
burs.append(s);
}
}
}