1553 lines
58 KiB
C++
1553 lines
58 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
//
|
|
// File: x86Emitter.cpp
|
|
//
|
|
// Authors: Peter DeSantis
|
|
// Simon Holmes a Court
|
|
//
|
|
|
|
// Temporary
|
|
// Some CL args I use:
|
|
// -sys javasoft/sqe/tests/api/java/lang/Boolean/BooleanTests1
|
|
// -stage i -method insertElementAt (Ljava/lang/Object;I)V java/util/Vector
|
|
// -stage -noinvoke i -method cmpLongTestHarnessHelper (JJ)I TinyClass
|
|
// -l Output -l Package TinyClass
|
|
// -breakCompile TinyClass Sieve ([I)V -html -log x86ArgList 4 -log x86Emitter 4 -log x86Spill 4 -log FieldOrMethod 4 -l Package -sys TinyClass
|
|
// -sys -html -log x86Emitter 4 -log FieldOrMethod 4 -ta -be java.lang.String startsWith (Ljava/lang/String;I)Z TinyClass
|
|
// -sys -html -be suntest.quicktest.runtime.QuickTest assert (ZLjava/lang/String;)V javasoft/sqe/tests/api/java/lang/Integer/IntegerTests32
|
|
|
|
#include "x86Emitter.h"
|
|
#include "x86Instruction.h"
|
|
#include "x86StdCall.h"
|
|
#include "Primitives.h"
|
|
#include "SysCalls.h"
|
|
#include "x86SysCallsRuntime.h"
|
|
#include "JavaObject.h"
|
|
|
|
#include "x86.nad.burg.h"
|
|
#include "ControlNodes.h"
|
|
|
|
#include "x86Instruction.h"
|
|
|
|
#include "x86ExceptionHandler.h"
|
|
|
|
UT_DEFINE_LOG_MODULE(x86Emitter);
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Debugging
|
|
|
|
|
|
#ifdef DEBUG_LOG_VERBOSE
|
|
// for rule printing
|
|
extern char* burm_string[];
|
|
extern int burm_max_rule;
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Emitter
|
|
|
|
// Structures/Enums
|
|
|
|
x86ArgumentType memDSIAddressingModes[] =
|
|
{
|
|
atBaseIndexed,
|
|
atScaledIndexedBy2,
|
|
atScaledIndexedBy4,
|
|
atScaledIndexedBy8
|
|
};
|
|
|
|
struct x86CondList
|
|
{
|
|
x86ConditionCode ccSigned;
|
|
x86ConditionCode ccUnsigned;
|
|
};
|
|
|
|
x86CondList condList[] =
|
|
{
|
|
// signed, unsigned
|
|
{ ccJL, ccJB }, // cLt
|
|
{ ccJE, ccJE }, // cEq
|
|
{ ccJLE, ccJBE }, // cLe
|
|
{ ccJNLE, ccJNBE }, // cGt
|
|
{ ccJNE, ccJNE }, // cLgt
|
|
{ ccJNL, ccJNB }, // cGe
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
void x86Emitter::
|
|
emitPrimitive(Primitive& inPrimitive, NamedRule inRule)
|
|
{
|
|
#ifdef DEBUG_LOG_VERBOSE // very noisy
|
|
char* ruleName;
|
|
if(inRule < burm_max_rule && (ruleName = burm_string[inRule]) != 0)
|
|
printf("[%3d] %-50s ", inRule, ruleName);
|
|
else
|
|
printf("[%3d] %-50s ", inRule, NULL);
|
|
#endif
|
|
|
|
// case statement corresponding to rules in the grammar
|
|
switch (inRule)
|
|
{
|
|
//-----------------------------------------------------------------------
|
|
// General
|
|
case emConst_I: emit_LoadConstant_I(inPrimitive); break;
|
|
case emConst_A: emit_LoadAddress(inPrimitive); break;
|
|
case emConst_L: emit_LoadConstant_L(inPrimitive); break;
|
|
case emConst_F: emit_LoadConstant_F(inPrimitive); break;
|
|
case emConst_D: emit_LoadConstant_D(inPrimitive); break;
|
|
|
|
case emResult_I: emit_Result_I(inPrimitive); break;
|
|
case emResult_A: emit_Result_I(inPrimitive); break;
|
|
case emResult_L: emit_Result_L(inPrimitive); break;
|
|
case emResult_F: emit_Result_F(inPrimitive); break;
|
|
case emResult_D: emit_Result_D(inPrimitive); break;
|
|
|
|
case emBreak: emit_Break(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Control Flow
|
|
case emIfLt: emit_B(inPrimitive, rawLt); break;
|
|
case emIfEq: emit_B(inPrimitive, rawEq); break;
|
|
case emIfLe: emit_B(inPrimitive, rawLe); break;
|
|
case emIfGt: emit_B(inPrimitive, rawGt); break;
|
|
case emIfLgt: emit_B(inPrimitive, rawLgt); break;
|
|
case emIfGe: emit_B(inPrimitive, rawGe); break;
|
|
|
|
case emIfULt: emit_B(inPrimitive, rawLt); break;
|
|
case emIfUEq: emit_B(inPrimitive, rawEq); break;
|
|
case emIfULe: emit_B(inPrimitive, rawLe); break;
|
|
case emIfUGt: emit_B(inPrimitive, rawGt); break;
|
|
case emIfNe: emit_B(inPrimitive, rawLgt); break;
|
|
case emIfUGe: emit_B(inPrimitive, rawGe); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Booleans
|
|
case emLt_I: emit_Cond(inPrimitive, rawLt); break;
|
|
case emEq_I: emit_Cond(inPrimitive, rawEq); break;
|
|
case emLe_I: emit_Cond(inPrimitive, rawLe); break;
|
|
case emGt_I: emit_Cond(inPrimitive, rawGt); break;
|
|
case emLgt_I: emit_Cond(inPrimitive, rawLgt); break;
|
|
case emGe_I: emit_Cond(inPrimitive, rawGe); break;
|
|
|
|
case emULt_I: emit_Cond(inPrimitive, rawLt); break;
|
|
case emUEq_I: emit_Cond(inPrimitive, rawEq); break;
|
|
case emULe_I: emit_Cond(inPrimitive, rawLe); break;
|
|
case emUGt_I: emit_Cond(inPrimitive, rawGt); break;
|
|
case emNe_I: emit_Cond(inPrimitive, rawLgt); break;
|
|
case emUGe_I: emit_Cond(inPrimitive, rawGe); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Switch
|
|
case emSwitch: emit_Switch(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Scalar and Aritmetic Logic
|
|
|
|
// And
|
|
case emAnd_I: emit_And_I(inPrimitive); break;
|
|
case emAndI_I: emit_AndI_I(inPrimitive); break;
|
|
|
|
case emAnd_L: emit_And_L(inPrimitive); break;
|
|
|
|
// Or
|
|
case emOr_I: emit_Or_I(inPrimitive); break;
|
|
case emOrI_I: emit_OrI_I(inPrimitive); break;
|
|
case emOr_L: emit_Or_L(inPrimitive); break;
|
|
|
|
// Xor
|
|
case emXor_I: emit_Xor_I(inPrimitive); break;
|
|
case emXorI_I: emit_XorI_I(inPrimitive); break;
|
|
|
|
case emXor_L: emit_Xor_L(inPrimitive); break;
|
|
|
|
// Add
|
|
case emAdd_I: emit_Add_I(inPrimitive); break;
|
|
case emAdd_A: emit_Add_I(inPrimitive); break;
|
|
|
|
case emAddI_I: emit_AddI_I(inPrimitive); break;
|
|
case emAddI_A: emit_AddI_I(inPrimitive); break;
|
|
|
|
case emAdd_L: emit_Add_L(inPrimitive); break;
|
|
|
|
// Sub
|
|
case emSub_I: emit_Sub_I(inPrimitive); break;
|
|
case emSub_A: emit_Sub_I(inPrimitive); break;
|
|
|
|
case emSub_L: emit_Sub_L(inPrimitive); break;
|
|
case emSubR_I: emit_SubR_I(inPrimitive); break;
|
|
|
|
// Mul
|
|
case emMul_I: emit_Mul_I(inPrimitive); break;
|
|
case emMul_L: emit_Mul_L(inPrimitive); break;
|
|
|
|
// Div
|
|
case emDiv_I: emit_Div_I(inPrimitive); break;
|
|
case emDivE_I: emit_Div_I(inPrimitive); break;
|
|
|
|
case emDiv_I_MemDSI: emit_Div_I_MemDSI(inPrimitive); break;
|
|
case emDivE_I_MemDSI: emit_Div_I_MemDSI(inPrimitive); break;
|
|
|
|
case emDivU_I: emit_DivU_I(inPrimitive); break;
|
|
case emDivUE_I: emit_DivU_I(inPrimitive); break;
|
|
|
|
case emDivU_I_MemDSI: emit_DivU_I_MemDSI(inPrimitive); break;
|
|
case emDivUE_I_MemDSI: emit_DivU_I_MemDSI(inPrimitive); break;
|
|
|
|
case emDiv_L: emit_Div_L(inPrimitive); break;
|
|
case emDivE_L: emit_Div_L(inPrimitive); break;
|
|
|
|
// Mod
|
|
case emMod_I: emit_Mod_I(inPrimitive); break;
|
|
case emModE_I: emit_Mod_I(inPrimitive); break;
|
|
|
|
case emMod_I_MemDSI: emit_Mod_I_MemDSI(inPrimitive); break;
|
|
case emModE_I_MemDSI: emit_Mod_I_MemDSI(inPrimitive); break;
|
|
|
|
case emModU_I: emit_ModU_I(inPrimitive); break;
|
|
case emModUE_I: emit_ModU_I(inPrimitive); break;
|
|
|
|
case emModU_I_MemDSI: emit_ModU_I_MemDSI(inPrimitive); break;
|
|
case emModUE_I_MemDSI: emit_ModU_I_MemDSI(inPrimitive); break;
|
|
|
|
case emMod_L: emit_Mod_L(inPrimitive); break;
|
|
case emModE_L: emit_Mod_L(inPrimitive); break;
|
|
|
|
// Shift
|
|
case emShl_I: emit_Shl_I(inPrimitive); break;
|
|
case emShlI_I: emit_ShlI_I(inPrimitive); break;
|
|
|
|
case emShr_I: emit_Sar_I(inPrimitive); break;
|
|
case emShrI_I: emit_SarI_I(inPrimitive); break;
|
|
|
|
case emShrU_I: emit_Shr_I(inPrimitive); break;
|
|
case emShrUI_I: emit_ShrI_I(inPrimitive); break;
|
|
|
|
case emShl_L: emit_Shl_L(inPrimitive); break;
|
|
case emShr_L: emit_Sar_L(inPrimitive); break;
|
|
case emShrU_L: emit_Shr_L(inPrimitive); break;
|
|
|
|
// Sign Extend
|
|
case emExt_I: emit_Ext_I(inPrimitive); break;
|
|
case emExt_L: emit_Ext_L(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Floating Point Arithmetic
|
|
|
|
case emFAdd_D: emit_FAdd_D(inPrimitive); break;
|
|
case emFAdd_F: emit_FAdd_F(inPrimitive); break;
|
|
|
|
case emFMul_D: emit_FMul_D(inPrimitive); break;
|
|
case emFMul_F: emit_FMul_F(inPrimitive); break;
|
|
|
|
case emFSub_D: emit_FSub_D(inPrimitive); break;
|
|
case emFSub_F: emit_FSub_F(inPrimitive); break;
|
|
|
|
case emFDiv_D: emit_FDiv_D(inPrimitive); break;
|
|
case emFDiv_F: emit_FDiv_F(inPrimitive); break;
|
|
|
|
case emFRem_D: emit_FRem_D(inPrimitive); break;
|
|
case emFRem_F: emit_FRem_F(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Integer conversion
|
|
case emConvI_L: emit_ConvI_L(inPrimitive); break;
|
|
case emConvL_I: emit_ConvL_I(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Float conversion
|
|
case emFConvI_F:
|
|
case emFConvI_D:
|
|
case emFConvL_F:
|
|
case emFConvL_D:
|
|
case emFConvF_I:
|
|
case emFConvF_L:
|
|
case emFConvF_D:
|
|
case emFConvD_I:
|
|
case emFConvD_L:
|
|
case emFConvD_F: emit_FConv(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Comparison
|
|
case emCmp_I: emit_Cmp_I(inPrimitive); break;
|
|
case emCmpU_I: emit_Cmp_I(inPrimitive); break;
|
|
case emCmpU_A: emit_Cmp_I(inPrimitive); break;
|
|
|
|
case emCmpI_I: emit_CmpI_I(inPrimitive); break;
|
|
case emCmpUI_I: emit_CmpI_I(inPrimitive); break;
|
|
|
|
case emCmpI_I_MemDSI: emit_CmpI_I_MemDSI(inPrimitive); break;
|
|
case emCmp_I_MemDSI: emit_Cmp_I_MemDSI(inPrimitive); break;
|
|
|
|
case em3wayCmpL_L: emit_3wayCmpL_L(inPrimitive); break;
|
|
case em3wayCmpCL_L: emit_3wayCmpCL_L(inPrimitive); break;
|
|
|
|
case em3wayCmpF_L: emit_3wayCmpF_L(inPrimitive); break;
|
|
case em3wayCmpF_G: emit_3wayCmpF_G(inPrimitive); break;
|
|
case em3wayCmpD_L: emit_3wayCmpD_L(inPrimitive); break;
|
|
case em3wayCmpD_G: emit_3wayCmpD_G(inPrimitive); break;
|
|
|
|
case em3wayCmpCF_L: emit_3wayCmpCF_L(inPrimitive); break;
|
|
case em3wayCmpCF_G: emit_3wayCmpCF_G(inPrimitive); break;
|
|
case em3wayCmpCD_L: emit_3wayCmpCD_L(inPrimitive); break;
|
|
case em3wayCmpCD_G: emit_3wayCmpCD_G(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Limit
|
|
case emLimitR: emit_LimitR(inPrimitive); break;
|
|
case emLimit: emit_Limit(inPrimitive); break;
|
|
case emLimitR_MemDisp: emit_LimitR_MemDisp(inPrimitive); break;
|
|
case emLimit_MemDisp: emit_Limit_MemDisp(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Cast
|
|
case emLimCast: emit_LimCast(inPrimitive); break;
|
|
case emChkCastI_A: emit_ChkCast_Const(inPrimitive); break;
|
|
case emChkCast_A: emit_ChkCast(inPrimitive); break;
|
|
case emChkCast_I: emit_ChkCast(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Memory
|
|
case emLd_I: genLd_I(inPrimitive); break;
|
|
case emLd_A: genLd_I(inPrimitive); break;
|
|
case emLd_L: emit_Ld_L(inPrimitive); break;
|
|
case emLd_F: emit_Ld_F(inPrimitive); break;
|
|
case emLd_D: emit_Ld_D(inPrimitive); break;
|
|
|
|
|
|
case emLd_I_MemDisp: emit_Ld_I_MemDisp(inPrimitive); break;
|
|
case emLd_I_MemDSI: emit_Ld_I_MemDSI(inPrimitive); break;
|
|
|
|
case emLdS_B: emit_LdS_B(inPrimitive); break;
|
|
case emLdU_B: emit_LdU_B(inPrimitive); break;
|
|
case emLdS_H: emit_LdS_H(inPrimitive); break;
|
|
case emLdU_H: emit_LdU_H(inPrimitive); break;
|
|
|
|
case emSt_I: emit_St_I(inPrimitive); break;
|
|
case emSt_A: emit_St_I(inPrimitive); break;
|
|
case emSt_L: emit_St_L(inPrimitive); break;
|
|
case emStI_I: emit_StI_I(inPrimitive); break;
|
|
|
|
case emSt_B: emit_St_B(inPrimitive); break;
|
|
case emSt_H: emit_St_H(inPrimitive); break;
|
|
|
|
case emStI_I_MemDisp: emit_StI_I_MemDisp(inPrimitive); break;
|
|
case emSt_I_MemDisp: emit_St_I_MemDisp(inPrimitive); break;
|
|
case emSt_I_MemDSI: emit_St_I_MemDSI(inPrimitive); break;
|
|
|
|
case emSt_F: emit_St_F(inPrimitive); break;
|
|
case emSt_D: emit_St_D(inPrimitive); break;
|
|
|
|
/* FIXME: Implement performance optimizations
|
|
|
|
case emLd_F_MemDisp:
|
|
case emLd_F_MemDSI:
|
|
case emLd_D_MemDisp:
|
|
case emLd_D_MemDSI: assert(0); break;
|
|
|
|
case emStI_F_MemDisp:
|
|
case emSt_F_MemDisp:
|
|
case emSt_F_MemDSI:
|
|
|
|
case emStI_D_MemDisp:
|
|
case emSt_D_MemDisp:
|
|
case emSt_D_MemDSI:
|
|
assert(0); break;
|
|
*/
|
|
|
|
case emCatch: emit_Catch(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Calls
|
|
case emStaticCall:
|
|
{
|
|
new(mPool) Call_(&inPrimitive, mPool, Call_::numberOfArguments(inPrimitive), Call_::hasReturnValue(inPrimitive), *this);
|
|
break;
|
|
}
|
|
case emDynamicCall:
|
|
{
|
|
new(mPool) CallD_(&inPrimitive, mPool, CallD_::numberOfArguments(inPrimitive), CallD_::hasReturnValue(inPrimitive), *this);
|
|
break;
|
|
}
|
|
case emSysCall: case emSysCallE:
|
|
{
|
|
new(mPool) CallS_( &inPrimitive, mPool, CallS_::numberOfArguments(inPrimitive), true, *this,
|
|
(void (*)()) static_cast<PrimSysCall*>(&inPrimitive)->sysCall.function);
|
|
break;
|
|
}
|
|
case emSysCallC: case emSysCallEC:
|
|
{
|
|
new(mPool) CallS_C( &inPrimitive, mPool,
|
|
CallS_C::numberOfArguments(inPrimitive), true, *this,
|
|
(void (*)()) static_cast<PrimSysCall*>(&inPrimitive)->sysCall.function);
|
|
break;
|
|
}
|
|
case emSysCallV: case emSysCallEV:
|
|
{
|
|
new(mPool) CallS_V( &inPrimitive, mPool,
|
|
CallS_V::numberOfArguments(inPrimitive), true, *this,
|
|
(void (*)()) static_cast<PrimSysCall*>(&inPrimitive)->sysCall.function);
|
|
break;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Monitors
|
|
case emMEnter: emit_MonitorEnter(inPrimitive); break;
|
|
case emMExit: emit_MonitorExit(inPrimitive); break;
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Misc
|
|
case emChkNull: emit_ChkNull(inPrimitive); break;
|
|
|
|
default:
|
|
#ifdef DEBUG_LOG_VERBOSE
|
|
printf(" (unimplemented)");
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_LOG_VERBOSE
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Utility
|
|
bool x86Emitter::
|
|
emitCopyAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& fromVr, VirtualRegister& toVr)
|
|
{
|
|
InsnDoubleOpDir& newInsn = newCopyInstruction(inDataNode, mPool);
|
|
newInsn.addUse(0, fromVr);
|
|
newInsn.addDefine(0, toVr);
|
|
newInsn.insertAfter(*where);
|
|
|
|
#if DEBUG
|
|
toVr.setDefiningInstruction(newInsn);
|
|
newInsn.checkIntegrity(); // ensure that everthing makes sense here
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void x86Emitter::
|
|
emitStoreAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& storedReg, VirtualRegister& stackReg)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inDataNode, mPool, raSaveReg, atRegDirect, atRegAllocStackSlot, 1, 1);
|
|
newInsn.addUse(0, storedReg);
|
|
newInsn.addDefine(0, stackReg);
|
|
newInsn.insertAfter(*where);
|
|
|
|
UT_LOG(x86Emitter, PR_LOG_DEBUG, (" emitStoreAfter (insn %p)\n", &newInsn));
|
|
#if DEBUG
|
|
newInsn.printDebug(UT_LOG_MODULE(x86Emitter));
|
|
newInsn.checkIntegrity(); // ensure that everthing makes sense here
|
|
#endif
|
|
}
|
|
|
|
void x86Emitter::
|
|
emitLoadAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& loadedReg, VirtualRegister& stackReg)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inDataNode, mPool, raLoadI, atRegAllocStackSlot, atRegDirect, 1, 1);
|
|
newInsn.addUse(0, stackReg);
|
|
newInsn.addDefine(0, loadedReg);
|
|
newInsn.insertAfter(*where);
|
|
|
|
#ifdef DEBUG // FIX why do you do this Laurent?
|
|
loadedReg.setDefiningInstruction(newInsn);
|
|
#endif
|
|
|
|
UT_LOG(x86Emitter, PR_LOG_DEBUG, (" emitLoadAfter (insn %p)\n", &newInsn));
|
|
#ifdef DEBUG
|
|
newInsn.printDebug(UT_LOG_MODULE(x86Emitter));
|
|
newInsn.printArgs();
|
|
newInsn.checkIntegrity(); // ensure that everthing makes sense here
|
|
#endif
|
|
}
|
|
|
|
Instruction& x86Emitter::
|
|
emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget)
|
|
{
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inDataNode, mPool, inTarget);
|
|
return (newInsn);
|
|
}
|
|
|
|
// COMMENT ME
|
|
VirtualRegister& x86Emitter::
|
|
emit_CopyOfInput(x86ArgListInstruction& /*inInsn*/, DataNode& inPrimitive, Uint8 inWhichInput, VirtualRegisterID inID)
|
|
{
|
|
// FIX-ME assumes fixed point registers
|
|
InsnDoubleOpDir& newInsn = newCopyInstruction(inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(inWhichInput), newInsn, 0, vrcInteger, inID);
|
|
VirtualRegister &vrToBeOverwritten = *defineProducer(inPrimitive, newInsn, 0, vrcInteger, inID);
|
|
return vrToBeOverwritten;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Arithmetic
|
|
/*
|
|
// Broken for now
|
|
void x86Emitter::
|
|
emit_MulI_I(Primitive& inPrimitive)
|
|
{
|
|
// FIX check for power of two
|
|
assert(false);
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, sMulImm, constant, atRegDirect, atRegDirect, 1, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 0);
|
|
defineProducer(inPrimitive, newInsn, 0);
|
|
}
|
|
*/
|
|
|
|
void x86Emitter::
|
|
emit_Mul_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOp& newInsn = *new(mPool) InsnDoubleOp(&inPrimitive, mPool, opMul);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_AddI_I(Primitive& inPrimitive)
|
|
{
|
|
x86Instruction* newInsn;
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
|
|
if(constant == 1) { // inc
|
|
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, ceInc, atRegDirect, 1, 1);
|
|
newInsn->x86StandardUseDefine(*this);
|
|
} else if((int)constant == -1) { // dec
|
|
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, ceDec, atRegDirect, 1, 1);
|
|
newInsn->x86StandardUseDefine(*this);
|
|
} else { // add
|
|
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, iaAddImm, constant, atRegDirect, 1, 1);
|
|
newInsn->x86StandardUseDefine(*this);
|
|
}
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Add_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raAdd);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Sub_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raSub);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
|
|
// a - b = (-b) + a
|
|
void x86Emitter::
|
|
emit_SubR_I(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 0);
|
|
|
|
// negate
|
|
x86Instruction& negInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, eNeg, atRegDirect, 1, 1 );
|
|
VirtualRegister& vrOut = emit_CopyOfInput(negInsn, inPrimitive, 1);
|
|
useProducer(inPrimitive, negInsn, 0);
|
|
redefineTemporary(negInsn, vrOut, 0);
|
|
|
|
// add constant
|
|
// FIX later work out how to avoid emitting
|
|
x86Instruction& addInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, iaAddImm, constant, atRegDirect, 1, 1);
|
|
useProducer(inPrimitive, addInsn, 0);
|
|
defineProducer(inPrimitive, addInsn, 0);
|
|
// FIX is this right
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Integer Logical Operations
|
|
|
|
void x86Emitter::emit_AndI_I(Primitive& inPrimitive) { genLogicI_I(inPrimitive, iaAndImm); }
|
|
void x86Emitter::emit_OrI_I(Primitive& inPrimitive) { genLogicI_I(inPrimitive, iaOrImm); }
|
|
void x86Emitter::emit_XorI_I(Primitive& inPrimitive) { genLogicI_I(inPrimitive, iaXorImm); }
|
|
|
|
void x86Emitter::emit_And_I(Primitive& inPrimitive) { genLogic_I(inPrimitive, raAnd); }
|
|
void x86Emitter::emit_Or_I(Primitive& inPrimitive) { genLogic_I(inPrimitive, raOr); }
|
|
void x86Emitter::emit_Xor_I(Primitive& inPrimitive) { genLogic_I(inPrimitive, raXor); }
|
|
|
|
void x86Emitter::
|
|
genLogicI_I(Primitive& inPrimitive, x86ImmediateArithType iaType)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, iaType, constant, atRegDirect, 1, 1);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
|
|
void x86Emitter::
|
|
genLogic_I(Primitive& inPrimitive, x86DoubleOpDirCode raType)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raType);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Integer Shifts
|
|
|
|
void x86Emitter::emit_SarI_I(Primitive& inPrimitive) { genShiftI_I(inPrimitive, eSarImm, eSar1); }
|
|
void x86Emitter::emit_ShrI_I(Primitive& inPrimitive) { genShiftI_I(inPrimitive, eShrImm, eShr1); }
|
|
void x86Emitter::emit_ShlI_I(Primitive& inPrimitive) { genShiftI_I(inPrimitive, eShlImm, eShl1); }
|
|
|
|
void x86Emitter::emit_Sar_I(Primitive& inPrimitive) { genShift_I(inPrimitive, eSarCl); }
|
|
void x86Emitter::emit_Shr_I(Primitive& inPrimitive) { genShift_I(inPrimitive, eShrCl); }
|
|
void x86Emitter::emit_Shl_I(Primitive& inPrimitive) { genShift_I(inPrimitive, eShlCl); }
|
|
|
|
void x86Emitter::genShiftI_I(Primitive& inPrimitive, x86ExtendedType eByImmediate, x86ExtendedType eBy1)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
if(constant == 1)
|
|
{
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, eBy1, atRegDirect, 1, 1);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, eByImmediate, constant, atRegDirect, 1, 1);
|
|
newInsn.x86StandardUseDefine(*this);
|
|
}
|
|
}
|
|
|
|
void x86Emitter::genShift_I(Primitive& inPrimitive, x86ExtendedType eByCl)
|
|
{
|
|
x86Instruction& shiftInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, eByCl, atRegDirect, 2, 1 );
|
|
|
|
// we kill one of our inputs, make copy
|
|
emit_CopyOfInput(shiftInsn, inPrimitive, 0);
|
|
|
|
// input and output arg 0 will have been copied to the outgoing edge
|
|
// by emit_CopyOfInput
|
|
useProducer(inPrimitive, shiftInsn, 0);
|
|
defineProducer(inPrimitive, shiftInsn, 0);
|
|
|
|
// now make a buffer copy of the shift by value so we can precolor
|
|
InsnDoubleOpDir& shiftByCopy = newCopyInstruction(inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(1), shiftByCopy, 0);
|
|
VirtualRegister& shiftByVR = defineTemporary(shiftByCopy, 0);
|
|
shiftByVR.preColorRegister(x86GPRToColor[ECX]);
|
|
|
|
// setup last input of the shift instruction
|
|
useTemporaryVR(shiftInsn, shiftByVR, 1);
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// 64 bit support
|
|
void x86Emitter::emit_Add_L(Primitive& inPrimitive) { emit_Arithmetic_L(inPrimitive, raAdd, raAdc); }
|
|
void x86Emitter::emit_Sub_L(Primitive& inPrimitive) { emit_Arithmetic_L(inPrimitive, raSub, raSbb); }
|
|
|
|
void x86Emitter::
|
|
emit_Arithmetic_L(Primitive& inPrimitive, x86DoubleOpDirCode insnTypeLo, x86DoubleOpDirCode insnTypeHi)
|
|
{
|
|
// low word arithmetic
|
|
InsnDoubleOpDir& insnLo = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, insnTypeLo, atRegDirect, atRegDirect, 2, 2);
|
|
VirtualRegister& vrLo = emit_CopyOfInput(insnLo, inPrimitive, 0, vidLow);
|
|
useProducer(inPrimitive, insnLo, 0, vrcInteger, vidLow);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnLo, 1, vrcInteger, vidLow);
|
|
redefineTemporary(insnLo, vrLo, 0);
|
|
insnLo.addDefine(1, udCond);
|
|
|
|
// high word arithmetic with carry
|
|
InsnDoubleOpDir& insnHi = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, insnTypeHi, atRegDirect, atRegDirect, 3, 1);
|
|
VirtualRegister& vrHi = emit_CopyOfInput(insnHi, inPrimitive, 0, vidHigh);
|
|
useProducer(inPrimitive, insnHi, 0, vrcInteger, vidHigh);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnHi, 1, vrcInteger, vidHigh);
|
|
insnHi.addUse(2, udCond);
|
|
insnHi.getInstructionUseBegin()[2].src = &insnLo; // FIX hack in lieu of temporary condition edge
|
|
redefineTemporary(insnHi, vrHi, 0);
|
|
}
|
|
|
|
|
|
void x86Emitter::emit_And_L(Primitive& inPrimitive) { emit_Logic_L(inPrimitive, raAnd); }
|
|
void x86Emitter::emit_Or_L(Primitive& inPrimitive) { emit_Logic_L(inPrimitive, raOr); }
|
|
void x86Emitter::emit_Xor_L(Primitive& inPrimitive) { emit_Logic_L(inPrimitive, raXor); }
|
|
|
|
void x86Emitter::
|
|
emit_Logic_L(Primitive& inPrimitive, x86DoubleOpDirCode insnType)
|
|
{
|
|
// low word
|
|
InsnDoubleOpDir& insnLo = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, insnType);
|
|
VirtualRegister& vrLo = emit_CopyOfInput(insnLo, inPrimitive, 0, vidLow);
|
|
useProducer(inPrimitive, insnLo, 0, vrcInteger, vidLow);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnLo, 1, vrcInteger, vidLow);
|
|
redefineTemporary(insnLo, vrLo, 0);
|
|
|
|
// high word
|
|
InsnDoubleOpDir& insnHi = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, insnType);
|
|
VirtualRegister& vrHi = emit_CopyOfInput(insnHi, inPrimitive, 0, vidHigh);
|
|
useProducer(inPrimitive, insnHi, 0, vrcInteger, vidHigh);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnHi, 1, vrcInteger, vidHigh);
|
|
redefineTemporary(insnHi, vrHi, 0);
|
|
}
|
|
|
|
#include "x86Arith64.h"
|
|
|
|
void x86Emitter::
|
|
emit_Mul_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Mul64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Div_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Div64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Mod_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Mod64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_3wayCmpL_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86ThreeWayCMP_L, &(inPrimitive.nthInputVariable(0)));
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_3wayCmpCL_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86ThreeWayCMP_L, &(inPrimitive.nthInputVariable(0)));
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Shl_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Shl64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Shr_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Shr64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Sar_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Sar64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Ext_L(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)())&x86Extract64Bit);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_ConvL_I(Primitive& inPrimitive)
|
|
{
|
|
// make a copy of the input and precolour it to EAX
|
|
InsnDoubleOpDir& copyOfInput = newCopyInstruction(inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), copyOfInput, 0);
|
|
VirtualRegister& vrIn = defineTemporary(copyOfInput, 0);
|
|
vrIn.preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
// create CDQ instruction, use vrIn and define vrHi and vrLo
|
|
InsnNoArgs& insnCdq = *new(mPool) InsnNoArgs(&inPrimitive, mPool, opCdq, 1, 2);
|
|
useTemporaryVR(insnCdq, vrIn, 0);
|
|
VirtualRegister& vrHi = defineTemporary(insnCdq, 0);
|
|
VirtualRegister& vrLo = defineTemporary(insnCdq, 1);
|
|
|
|
// precolour vrHi and vrLo
|
|
vrHi.preColorRegister(x86GPRToColor[EDX]);
|
|
vrLo.preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
// make copies of vrHi and vrLo and define the producer
|
|
InsnDoubleOpDir& copyHi = newCopyInstruction(inPrimitive, mPool);
|
|
useTemporaryVR(copyHi, vrHi, 0);
|
|
defineProducer(inPrimitive, copyHi, 0, vrcInteger, vidHigh);
|
|
|
|
InsnDoubleOpDir& copyLo = newCopyInstruction(inPrimitive, mPool);
|
|
useTemporaryVR(copyLo, vrLo, 0);
|
|
defineProducer(inPrimitive, copyLo, 0, vrcInteger, vidLow);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_ConvI_L(Primitive& inPrimitive)
|
|
{
|
|
// make a copy of the low register of the input
|
|
InsnDoubleOpDir& copyOfInput = newCopyInstruction(inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), copyOfInput, 0, vrcInteger, vidLow);
|
|
defineProducer(inPrimitive, copyOfInput, 0);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Ld_L(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& insnLo = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, atRegisterIndirect, atRegDirect, 2, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), insnLo, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), insnLo, 0); // address
|
|
defineProducer(inPrimitive, insnLo, 0, vrcInteger, vidLow); // -> lo
|
|
|
|
InsnDoubleOpDir& insnHi = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, 4, atRegisterIndirect, atRegDirect, 2, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), insnHi, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), insnHi, 0); // address
|
|
defineProducer(inPrimitive, insnHi, 0, vrcInteger, vidHigh); // -> hi
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_St_L(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& insnLo = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreI, atRegisterIndirect, atRegDirect, 2, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnLo, 0); // address
|
|
useProducer(inPrimitive.nthInputVariable(2), insnLo, 1, vrcInteger, vidLow); // <- lo
|
|
// FIX for now these are commented out -- see comment below
|
|
// useProducer(inPrimitive.nthInputVariable(0), insnLo, 2); // memory edge in
|
|
// defineProducer(inPrimitive, insnLo, 0); // memory edge out
|
|
InstructionDefine& define = defineTemporaryOrder(insnLo, 0);
|
|
|
|
// FIX for now we are using the memory edge out from lo as the memory edge in for hi.
|
|
// This is because the memory edges don't have a clue about high/low registers
|
|
InsnDoubleOpDir& insnHi = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreI, 4, atRegisterIndirect, atRegDirect, 4, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnHi, 0); // address
|
|
useProducer(inPrimitive.nthInputVariable(2), insnHi, 1, vrcInteger, vidHigh); // <- hi
|
|
useProducer(inPrimitive.nthInputVariable(0), insnHi, 2); // memory edge in
|
|
useTemporaryOrder(insnHi, define, 3);
|
|
defineProducer(inPrimitive, insnHi, 0); // memory edge out
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
void x86Emitter::
|
|
emit_Break(Primitive& inPrimitive)
|
|
{
|
|
new(mPool) InsnNoArgs(&inPrimitive, mPool, opBreak, 0, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Comparisons
|
|
|
|
void x86Emitter::
|
|
emit_Cmp_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCmp);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_CmpI_I(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
|
|
if(constant == 0)
|
|
{
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, srmCmpImm0, 0, 1, 1 );
|
|
newInsn.standardUseDefine(*this);
|
|
} else {
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, iaCmpImm, constant, atRegDirect, 1, 1 );
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Div and Mod are very similar in X86, so we try to factor out as much as we can
|
|
|
|
// Normal Addressing Modes
|
|
void x86Emitter::emit_Div_I(Primitive& p) { genDivBackEnd(genDivMod_FrontEnd(p, eIDiv)); }
|
|
void x86Emitter::emit_DivU_I(Primitive& p) { genDivBackEnd(genDivMod_FrontEnd(p, eDiv )); }
|
|
void x86Emitter::emit_Mod_I(Primitive& p) { genModBackEnd(genDivMod_FrontEnd(p, eIDiv)); }
|
|
void x86Emitter::emit_ModU_I(Primitive& p) { genModBackEnd(genDivMod_FrontEnd(p, eDiv )); }
|
|
|
|
// Displaced, Scaled, Indexed Addressing Mode
|
|
void x86Emitter::emit_Div_I_MemDSI(Primitive& p) { genDivBackEnd(genDivMod_FrontEnd_MemDSI(p, eIDiv)); }
|
|
void x86Emitter::emit_DivU_I_MemDSI(Primitive& p) { genDivBackEnd(genDivMod_FrontEnd_MemDSI(p, eDiv )); }
|
|
void x86Emitter::emit_Mod_I_MemDSI(Primitive& p) { genModBackEnd(genDivMod_FrontEnd_MemDSI(p, eIDiv)); }
|
|
void x86Emitter::emit_ModU_I_MemDSI(Primitive& p) { genModBackEnd(genDivMod_FrontEnd_MemDSI(p, eDiv )); }
|
|
|
|
// does div, mod, divU, modU
|
|
// div divides dividend in EAX:EDX by divisor in reg/mem
|
|
x86Instruction& x86Emitter::
|
|
genDivMod_FrontEnd(Primitive& inPrimitive, x86ExtendedType insnType)
|
|
{
|
|
// make a copy of the dividend (since it will be eventually overwritten)
|
|
InsnDoubleOpDir& dividendCopy = newCopyInstruction(inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), dividendCopy, 0);
|
|
VirtualRegister& vrEAXin = defineTemporary(dividendCopy, 0);
|
|
vrEAXin.preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
// convert to quad word
|
|
InsnNoArgs& insnCdq = *new(mPool) InsnNoArgs(&inPrimitive, mPool, opCdq, 1, 2);
|
|
useTemporaryVR(insnCdq, vrEAXin, 0);
|
|
VirtualRegister& vrEAXOut = defineTemporary(insnCdq, 0);
|
|
VirtualRegister& vrEDXOut = defineTemporary(insnCdq, 1);
|
|
vrEAXOut.preColorRegister(x86GPRToColor[EAX]);
|
|
vrEDXOut.preColorRegister(x86GPRToColor[EDX]);
|
|
|
|
// divide
|
|
x86Instruction& insnDivide = *new(mPool)x86Instruction(&inPrimitive, mPool, insnType, atRegDirect, 3, 2);
|
|
useProducer(inPrimitive.nthInputVariable(1), insnDivide, 0);
|
|
useTemporaryVR(insnDivide, vrEAXOut, 1);
|
|
useTemporaryVR(insnDivide, vrEDXOut, 2);
|
|
|
|
return insnDivide;
|
|
}
|
|
|
|
// poDiv_I(Vint, MemDSI)
|
|
// dividend / divisor
|
|
x86Instruction& x86Emitter::
|
|
genDivMod_FrontEnd_MemDSI(Primitive& inPrimitive, x86ExtendedType insnType)
|
|
{
|
|
// get the DSI parameters
|
|
DataNode& loadPrimitive = inPrimitive.nthInputVariable(1);
|
|
|
|
MemDSIParameters parms(loadPrimitive);
|
|
assert(parms.scale <= 3); // eventually MemDSI will be limited to scale <=3
|
|
|
|
// make a copy of the dividend (since it will be eventually overwritten)
|
|
InsnDoubleOpDir& dividendCopy = newCopyInstruction(inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), dividendCopy, 0);
|
|
VirtualRegister& vrEAXin = defineTemporary(dividendCopy, 0);
|
|
vrEAXin.preColorRegister(x86GPRToColor[EAX]); // input must be in EAX
|
|
|
|
// convert to quad word
|
|
InsnNoArgs& insnCdq = *new(mPool) InsnNoArgs(&inPrimitive, mPool, opCdq, 1, 2);
|
|
useTemporaryVR(insnCdq, vrEAXin, 0);
|
|
VirtualRegister& vrEAXOut = defineTemporary(insnCdq, 0);
|
|
VirtualRegister& vrEDXOut = defineTemporary(insnCdq, 1);
|
|
vrEAXOut.preColorRegister(x86GPRToColor[EAX]);
|
|
vrEDXOut.preColorRegister(x86GPRToColor[EDX]);
|
|
|
|
// divide
|
|
x86Instruction& insnDivide =
|
|
*new(mPool)x86Instruction(&inPrimitive, mPool, insnType, memDSIAddressingModes[parms.scale], parms.displacement, 5, 2);
|
|
|
|
useProducer(parms.baseProducer, insnDivide, 0); // base
|
|
useProducer(parms.indexProducer, insnDivide, 1); // index
|
|
useTemporaryVR(insnDivide, vrEAXOut, 2); // EAX
|
|
useTemporaryVR(insnDivide, vrEDXOut, 3); // EDX
|
|
useProducer(loadPrimitive.nthInputVariable(0), insnDivide, 4); // memory edge in
|
|
|
|
return insnDivide;
|
|
}
|
|
|
|
// backends for div and mod
|
|
void x86Emitter::
|
|
genDivBackEnd(x86Instruction& inInsn)
|
|
{
|
|
DataNode& primitive = *(inInsn.getPrimitive());
|
|
VirtualRegister *vrEAX, *vrEDX;
|
|
|
|
vrEAX = &defineTemporary(inInsn, 0);
|
|
vrEAX->preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
InsnDoubleOpDir& insnCopy = newCopyInstruction(primitive, mPool);
|
|
useTemporaryVR(insnCopy, *vrEAX, 0);
|
|
defineProducer(primitive, insnCopy, 0);
|
|
|
|
vrEDX = &defineTemporary(inInsn, 1); // unused result
|
|
vrEDX->preColorRegister(x86GPRToColor[EDX]);
|
|
}
|
|
|
|
void x86Emitter::
|
|
genModBackEnd(x86Instruction& inInsn)
|
|
{
|
|
DataNode& primitive = *(inInsn.getPrimitive());
|
|
VirtualRegister *vrEAX, *vrEDX;
|
|
|
|
vrEDX = &defineTemporary(inInsn, 1);
|
|
vrEDX->preColorRegister(x86GPRToColor[EDX]);
|
|
|
|
InsnDoubleOpDir& insnCopy = newCopyInstruction(primitive, mPool);
|
|
useTemporaryVR(insnCopy, *vrEDX, 0);
|
|
defineProducer(primitive, insnCopy, 0);
|
|
|
|
vrEAX = &defineTemporary(inInsn, 0); // unused result
|
|
vrEAX->preColorRegister(x86GPRToColor[EAX]);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
void x86Emitter::
|
|
emit_LoadConstant_I(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = (*static_cast<const PrimConst *>(&inPrimitive)).value.i;
|
|
|
|
x86Instruction* newInsn;
|
|
|
|
if(constant == 0)
|
|
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, srmMoveImm0, 0, 0, 1);
|
|
else
|
|
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, ceMoveImm, constant, atRegDirect, 0, 1);
|
|
|
|
defineProducer(inPrimitive, *newInsn, 0);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LoadConstant_L(Primitive& inPrimitive)
|
|
{
|
|
Int64 constant = (*static_cast<const PrimConst *>(&inPrimitive)).value.l;
|
|
// FIX make better
|
|
Int32 low = (Int32)((Uint64) constant & 0xFFFFFFFF);
|
|
Int32 high = (Int32)((Uint64)constant >> 32);
|
|
|
|
x86Instruction* loInsn;
|
|
x86Instruction* hiInsn;
|
|
|
|
if(low == 0)
|
|
loInsn = new(mPool) x86Instruction(&inPrimitive, mPool, srmMoveImm0, 0, 0, 1);
|
|
else
|
|
loInsn = new(mPool) x86Instruction(&inPrimitive, mPool, ceMoveImm, low, atRegDirect, 0, 1);
|
|
defineProducer(inPrimitive, *loInsn, 0, vrcInteger, vidLow);
|
|
|
|
if(high == 0)
|
|
hiInsn = new(mPool) x86Instruction(&inPrimitive, mPool, srmMoveImm0, 0, 0, 1);
|
|
else
|
|
hiInsn = new(mPool) x86Instruction(&inPrimitive, mPool, ceMoveImm, high, atRegDirect, 0, 1);
|
|
defineProducer(inPrimitive, *hiInsn, 0, vrcInteger, vidHigh);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Catch(Primitive& inPrimitive)
|
|
{
|
|
// create a define instruction which tells the register allocator that the register
|
|
// is defined elsewhere (in the exception support code)
|
|
InsnExternalDefine& defineInsn = *new(mPool) InsnExternalDefine(&inPrimitive, mPool, 1);
|
|
|
|
// define an outgoing edge which is a vr precolored to EAX
|
|
VirtualRegister& exceptionObj = defineTemporary(defineInsn, 0);
|
|
exceptionObj.preColorRegister(x86GPRToColor[ECX]); // FIX should be eax (hack to work around reg alloc bug
|
|
|
|
// now create a buffer copy between the precolored EAX and define the outgoing
|
|
// VR with the outgoing edge of the Catch primitive
|
|
InsnDoubleOpDir& copyInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegDirect, atRegDirect, 1, 1);
|
|
useTemporaryVR(copyInsn, exceptionObj, 0);
|
|
defineProducer(inPrimitive, copyInsn, 0);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LoadAddress(Primitive& inPrimitive)
|
|
{
|
|
addr a= (*static_cast<const PrimConst *>(&inPrimitive)).value.a;
|
|
Uint32 constant = (Uint32)addressFunction(a);
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, ceMoveImm, constant, atRegDirect, 0, 1);
|
|
defineProducer(inPrimitive, newInsn, 0);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Ext_I(Primitive& inPrimitive)
|
|
{
|
|
Uint32 shiftAmount = 32 - nthInputConstantUint32(inPrimitive, 1);
|
|
|
|
// shift left by shiftAmount
|
|
x86Instruction& shl = *new(mPool) x86Instruction(&inPrimitive, mPool, eShlImm, shiftAmount, atRegDirect, 1, 1);
|
|
shl.x86StandardUseDefine(*this);
|
|
|
|
// sar by shiftAmount
|
|
x86Instruction& sar = *new(mPool) x86Instruction(&inPrimitive, mPool, eSarImm, shiftAmount, atRegDirect, 1, 1);
|
|
useProducer(inPrimitive, sar, 0);
|
|
defineProducer(inPrimitive, sar, 0);
|
|
}
|
|
|
|
// Method: emit_Switch
|
|
// Purpose: emit a switch
|
|
void x86Emitter::
|
|
emit_Switch(Primitive& inPrimitive)
|
|
{
|
|
InsnSwitch& jmpInsn = *new InsnSwitch(&inPrimitive, mPool);
|
|
jmpInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
// Method: getConditionCode
|
|
// Purpose: check the condition edge we depend upon to see if it is signed or unsigned and
|
|
// use it to select the x86 condition code
|
|
// Assumes: condition edge is always the 0th input (currently an invariant)
|
|
inline x86ConditionCode getConditionCode(Primitive& inPrimitive, RawConditionCode rawCondType)
|
|
{
|
|
x86ConditionCode condType;
|
|
if(inPrimitive.nthInputVariable(0).isSignedCompare())
|
|
condType = condList[rawCondType].ccSigned;
|
|
else
|
|
condType = condList[rawCondType].ccUnsigned;
|
|
return condType;
|
|
}
|
|
|
|
// Method: emit_B
|
|
// Purpose: emit a conditional branch
|
|
void x86Emitter::
|
|
emit_B(Primitive& inPrimitive, RawConditionCode rawCondType)
|
|
{
|
|
// since the condition code depends on whether the comparison was signed or unsinged,
|
|
// we need to determine whether the comparison primitive preceding this primitive was
|
|
// signed or unsigned and use that to select the appropriate condition code.
|
|
x86ConditionCode condType = getConditionCode(inPrimitive, rawCondType);
|
|
|
|
// conditional branch
|
|
ControlNode& controlIf = *inPrimitive.getContainer();
|
|
InsnCondBranch& newInsn = *new(mPool) InsnCondBranch(&inPrimitive, mPool, condType, controlIf);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
// Method: emit_Cond
|
|
// Purpose: emit a condition flags -> boolean conversion
|
|
// Code must be in the form
|
|
// xor eax,eax WE EMIT
|
|
// cmp ecx, value (emitted by CMP primitive)
|
|
// sete al WE EMIT
|
|
// [copy al, tempVr] WE EMIT (tempVR is in the outgoing edge)
|
|
//
|
|
// It is imperative that the instruction scheduler clears the destination before the comparison,
|
|
// otherwise the compare flags will be clobbered by the xor eax, eax
|
|
void x86Emitter::
|
|
emit_Cond(Primitive& inPrimitive, RawConditionCode rawCondType)
|
|
{
|
|
// see comment in emit_B
|
|
x86ConditionCode condType = getConditionCode(inPrimitive, rawCondType);
|
|
|
|
// clear the destination
|
|
x86Instruction& clearInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, srmMoveImm0, 0, 0, 1);
|
|
VirtualRegister& outputVR = defineTemporary(clearInsn,0);
|
|
outputVR.preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
// set instruction
|
|
InsnSet& setInsn = *new(mPool) InsnSet(&inPrimitive, mPool, condType);
|
|
useTemporaryVR(setInsn, outputVR, 0); // register to store into
|
|
useProducer(inPrimitive.nthInputVariable(0), setInsn, 1); // condition edge
|
|
redefineTemporary(setInsn, outputVR, 0); // -> result
|
|
|
|
// create buffer copy
|
|
InsnDoubleOpDir& copyInsn = newCopyInstruction(inPrimitive, mPool);
|
|
useTemporaryVR(copyInsn, outputVR, 0);
|
|
defineProducer(inPrimitive, copyInsn, 0);
|
|
}
|
|
|
|
void x86Emitter::
|
|
genLd_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, atRegisterIndirect, atRegDirect);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
defineProducer(inPrimitive, newInsn, 0); // output
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LdS_B(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOp& newInsn = *new(mPool) InsnDoubleOp(&inPrimitive, mPool, opMovSxB, atRegisterIndirect, atRegDirect);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
defineProducer(inPrimitive, newInsn, 0); // output
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LdU_B(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOp& newInsn = *new(mPool) InsnDoubleOp(&inPrimitive, mPool, opMovZxB, atRegisterIndirect, atRegDirect);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
defineProducer(inPrimitive, newInsn, 0); // output
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LdS_H(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOp& newInsn = *new(mPool) InsnDoubleOp(&inPrimitive, mPool, opMovSxH, atRegisterIndirect, atRegDirect);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
defineProducer(inPrimitive, newInsn, 0); // output
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LdU_H(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOp& newInsn = *new(mPool) InsnDoubleOp(&inPrimitive, mPool, opMovZxH, atRegisterIndirect, atRegDirect);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
defineProducer(inPrimitive, newInsn, 0); // output
|
|
}
|
|
|
|
void x86Emitter::
|
|
genLdC_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, atRegisterIndirect, atRegDirect, 1, 1);
|
|
defineProducer(inPrimitive, newInsn, 0);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 0);
|
|
|
|
/* FIX pete -- why
|
|
put a flag in for exceptions here!!!!
|
|
use curIndex as the place to put it */
|
|
}
|
|
|
|
// poLimit(Vint, Vint) throw if va >= vb (ie ensure va < vb) OK
|
|
// form cmp r1, r2 throw if r1 >= r2 r1 nb r2
|
|
// so skip if !nb ==> b
|
|
void x86Emitter::
|
|
emit_Limit(Primitive& inPrimitive)
|
|
{
|
|
// compare
|
|
InsnDoubleOpDir& compare = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCmp);
|
|
useProducer(inPrimitive.nthInputVariable(0), compare, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), compare, 1);
|
|
compare.addDefine(0, udCond);
|
|
|
|
// branch
|
|
// jump to exception handler >= ie jnb
|
|
InsnSysCallCondBranch& branch = *new(mPool) InsnSysCallCondBranch(&inPrimitive, mPool, ccJB, (void (*)())sysThrowArrayIndexOutOfBoundsException);
|
|
branch.addUse(0, udCond);
|
|
branch.getInstructionUseBegin()->src = &compare;
|
|
inPrimitive.setInstructionRoot(&branch);
|
|
}
|
|
|
|
// Common code for limCast, chkCast and chkNull primitives
|
|
void x86Emitter::
|
|
emit_ExceptionCheck(Primitive& inPrimitive, x86ConditionCode condType, Uint32 constant, void (*throwExceptionFunction)())
|
|
{
|
|
x86Instruction& trap = *new(mPool) x86Instruction(&inPrimitive, mPool, iaCmpImm, constant, atRegDirect, 1, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), trap, 0);
|
|
trap.addDefine(0, udCond);
|
|
|
|
// branch
|
|
InsnSysCallCondBranch& branch = *new(mPool) InsnSysCallCondBranch(&inPrimitive, mPool, condType, throwExceptionFunction);
|
|
branch.addUse(0, udCond);
|
|
branch.getInstructionUseBegin()->src = &trap;
|
|
inPrimitive.setInstructionRoot(&branch);
|
|
}
|
|
|
|
// poChkCast_I(vint, Vint) or poChkCast_A(Vptr, Vptr)
|
|
void x86Emitter::
|
|
emit_ChkCast(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& trap = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCmp);
|
|
useProducer(inPrimitive.nthInputVariable(0), trap, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), trap, 1);
|
|
trap.addDefine(0, udCond);
|
|
|
|
// branch
|
|
InsnSysCallCondBranch& branch = *new(mPool) InsnSysCallCondBranch(&inPrimitive, mPool, ccJE, (void (*)())sysThrowClassCastException);
|
|
branch.addUse(0, udCond);
|
|
branch.getInstructionUseBegin()->src = &trap;
|
|
inPrimitive.setInstructionRoot(&branch);
|
|
}
|
|
|
|
// poChkCast_A(Vptr, Cptr)
|
|
void x86Emitter::
|
|
emit_ChkCast_Const(Primitive& inPrimitive)
|
|
{
|
|
Uint32 classPtr = nthInputConstantUint32(inPrimitive, 1);
|
|
emit_ExceptionCheck(inPrimitive, ccJE, classPtr, (void (*)())sysThrowClassCastException);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_LimCast(Primitive& inPrimitive)
|
|
{
|
|
Uint32 numVTableEntries = nthInputConstantUint32(inPrimitive, 1);
|
|
emit_ExceptionCheck(inPrimitive, ccJNB, numVTableEntries, (void (*)())sysThrowClassCastException);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_ChkNull(Primitive& inPrimitive)
|
|
{
|
|
emit_ExceptionCheck(inPrimitive, ccJNE, 0, (void (*)())sysThrowNullPointerException);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Result_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& copyInsn = newCopyInstruction(inPrimitive, mPool);
|
|
InsnExternalUse& extInsn = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0);
|
|
VirtualRegister& resultReg = defineTemporary(copyInsn, 0);
|
|
resultReg.preColorRegister(x86GPRToColor[EAX]);
|
|
useTemporaryVR(extInsn, resultReg, 0);
|
|
inPrimitive.setInstructionRoot(&extInsn);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Result_L(Primitive& inPrimitive)
|
|
{
|
|
// Low
|
|
InsnDoubleOpDir& copyLo = newCopyInstruction(inPrimitive, mPool, 1, 2);
|
|
InsnExternalUse& extLoInsn = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), copyLo, 0, vrcInteger, vidLow);
|
|
VirtualRegister& vrLo = defineTemporary(copyLo, 0);
|
|
vrLo.preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
useTemporaryVR(extLoInsn, vrLo, 0);
|
|
|
|
// High
|
|
InsnDoubleOpDir& copyHi = newCopyInstruction(inPrimitive, mPool, 2, 1);
|
|
InsnExternalUse& extHiInsn = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), copyHi, 0, vrcInteger, vidHigh);
|
|
VirtualRegister& vrHi = defineTemporary(copyHi, 0);
|
|
vrHi.preColorRegister(x86GPRToColor[EDX]);
|
|
|
|
useTemporaryVR(extHiInsn, vrHi, 0);
|
|
useTemporaryOrder(copyHi, defineTemporaryOrder(copyLo, 1), 1);
|
|
|
|
inPrimitive.setInstructionRoot(&extHiInsn);
|
|
}
|
|
|
|
// poLimit(poConst_I, Vint) throw if poConst_I >= Vint OK
|
|
// form cmp reg, 10 throw if poConst_I <= Vint jbe
|
|
// so skip if !be ==> jnbe
|
|
void x86Emitter::
|
|
emit_LimitR(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
|
|
// compare
|
|
x86Instruction& compare = *new(mPool) x86Instruction(&inPrimitive, mPool, iaCmpImm, constant, atRegDirect, 1, 1 );
|
|
useProducer(inPrimitive.nthInputVariable(1), compare, 0);
|
|
compare.addDefine(0, udCond);
|
|
|
|
// branch
|
|
// reversed -- jump to exception handler if below or equal ie ccJBE (ok)
|
|
InsnSysCallCondBranch& branch = *new(mPool) InsnSysCallCondBranch(&inPrimitive, mPool, ccJNBE, (void (*)())sysThrowArrayIndexOutOfBoundsException);
|
|
branch.addUse(0, udCond);
|
|
branch.getInstructionUseBegin()->src = &compare;
|
|
inPrimitive.setInstructionRoot(&branch);
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_St_I(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreI, atRegisterIndirect, atRegDirect, 3, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // adress
|
|
useProducer(inPrimitive.nthInputVariable(2), newInsn, 1); // data
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 2); // memory edge in
|
|
defineProducer(inPrimitive, newInsn, 0); // memory edge out
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_St_B(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreB, atRegisterIndirect, atRegDirect, 3, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
|
|
// FIX precolouring until register classes are introduced
|
|
InsnDoubleOpDir& copyInsn = newCopyInstruction(inPrimitive, mPool);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(2), copyInsn, 0); // data
|
|
VirtualRegister& copyOfInput = defineTemporary(copyInsn, 0);
|
|
|
|
copyOfInput.preColorRegister(x86GPRToColor[EAX]);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 2); // memory edge in
|
|
useTemporaryVR(newInsn, copyOfInput, 1); // precolored register containing the data
|
|
defineProducer(inPrimitive, newInsn, 0); // memory edge out
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_St_H(Primitive& inPrimitive)
|
|
{
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreH, atRegisterIndirect, atRegDirect, 3, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // adress
|
|
useProducer(inPrimitive.nthInputVariable(2), newInsn, 1); // data
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 2); // memory edge in
|
|
defineProducer(inPrimitive, newInsn, 0); // memory edge out
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_StI_I(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 2);
|
|
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, eMoveImm, constant, atRegisterIndirect, 2, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0); // address
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge in
|
|
defineProducer(inPrimitive, newInsn, 0); // memory edge out
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// MemDisp
|
|
void x86Emitter::
|
|
emit_St_I_MemDisp(Primitive& inPrimitive)
|
|
{
|
|
DataNode& addSource = inPrimitive.nthInput(1).getVariable();
|
|
Uint32 disp = nthInputConstantUint32(addSource, 1);
|
|
|
|
// store
|
|
InsnDoubleOpDir& newInsn =
|
|
*new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreI, disp, atRegisterIndirect, atRegDirect, 3, 1);
|
|
useProducer(addSource.nthInputVariable(0), newInsn, 0); // base address
|
|
useProducer(inPrimitive.nthInputVariable(2), newInsn, 1); // value to store
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 2); // memory edge in
|
|
defineProducer(inPrimitive, newInsn, 0); // memory edge out
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_StI_I_MemDisp(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 2);
|
|
|
|
DataNode& addSource = inPrimitive.nthInput(1).getVariable();
|
|
Uint32 disp = nthInputConstantUint32(addSource, 1);
|
|
|
|
// store
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, eMoveImm, constant, atRegisterIndirect, disp, 2, 1);
|
|
useProducer(addSource.nthInputVariable(0), newInsn, 0); // base address
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge in
|
|
defineProducer(inPrimitive, newInsn, 0); // memory edge out
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Ld_I_MemDisp(Primitive& inPrimitive)
|
|
{
|
|
DataNode& addSource = inPrimitive.nthInput(1).getVariable();
|
|
Uint32 disp = nthInputConstantUint32(addSource, 1);
|
|
|
|
// load
|
|
InsnDoubleOpDir& newInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, disp, atRegisterIndirect, atRegDirect);
|
|
useProducer(addSource.nthInputVariable(0), newInsn, 0); // base address
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1); // memory edge
|
|
defineProducer(inPrimitive, newInsn, 0); // loaded value
|
|
}
|
|
|
|
// poLimit(poConst_I, MemDisp) throw if poConst_I >= MemDisp OK
|
|
// form cmp [eax + 4], 10 throw if MemDisp <= poConst_I jbe
|
|
// so skip if !be ==> jnbe
|
|
void x86Emitter::
|
|
emit_LimitR_MemDisp(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 0);
|
|
|
|
DataNode& loadSource = inPrimitive.nthInput(1).getVariable();
|
|
DataNode& addSource = loadSource.nthInput(1).getVariable();
|
|
Uint32 displacement = nthInputConstantUint32(addSource, 1);
|
|
|
|
x86Instruction& compare = *new(mPool) x86Instruction(&inPrimitive, mPool, iaCmpImm, constant, atRegisterIndirect, displacement, 1, 1);
|
|
useProducer(addSource.nthInputVariable(0), compare, 0);
|
|
compare.addDefine(0, udCond);
|
|
|
|
// reversed -- jump to exception handler if below ie ccJBE
|
|
InsnSysCallCondBranch& branch = *new(mPool) InsnSysCallCondBranch(&inPrimitive, mPool, ccJNBE, (void (*)())sysThrowArrayIndexOutOfBoundsException);
|
|
branch.addUse(0, udCond);
|
|
branch.getInstructionUseBegin()->src = &compare;
|
|
inPrimitive.setInstructionRoot(&branch);
|
|
}
|
|
|
|
// poLimit(Vint, MemDisp) throw if Vint >= MemDisp OK
|
|
// form cmp eax, [reg + 4] throw if Vint >= MemDisp jnb
|
|
// so skip if !nb ==> jb
|
|
void x86Emitter::
|
|
emit_Limit_MemDisp(Primitive& inPrimitive)
|
|
{
|
|
DataNode& loadSource = inPrimitive.nthInput(1).getVariable();
|
|
DataNode& addSource = loadSource.nthInput(1).getVariable();
|
|
Uint32 displacement = nthInputConstantUint32(addSource, 1);
|
|
|
|
// compare
|
|
InsnDoubleOpDir& compare = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCmp, displacement, atRegDirect, atRegisterIndirect);
|
|
useProducer(inPrimitive.nthInputVariable(0), compare, 0);
|
|
useProducer(addSource.nthInputVariable(0), compare, 1);
|
|
compare.addDefine(0, udCond);
|
|
|
|
// branch
|
|
InsnSysCallCondBranch& branch = *new(mPool) InsnSysCallCondBranch(&inPrimitive, mPool, ccJB, (void (*)())sysThrowArrayIndexOutOfBoundsException);
|
|
branch.addUse(0, udCond);
|
|
branch.getInstructionUseBegin()->src = &compare;
|
|
inPrimitive.setInstructionRoot(&branch);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// MemDSI -- lots more factoring out to do
|
|
|
|
// poCmp_I(MemDSI, Vint)
|
|
void x86Emitter::
|
|
emit_Cmp_I_MemDSI(Primitive& inPrimitive)
|
|
{
|
|
DataNode& loadPrimitive = inPrimitive.nthInput(0).getVariable();
|
|
MemDSIParameters parms(loadPrimitive);
|
|
assert(parms.scale <= 3); // eventually MemDSI will be limited to scale <=3
|
|
|
|
InsnDoubleOpDir& newInsn =
|
|
*new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCmp, parms.displacement, memDSIAddressingModes[parms.scale], atRegDirect, 4, 1);
|
|
useProducer(parms.baseProducer, newInsn, 0); // <- base
|
|
useProducer(parms.indexProducer, newInsn, 1); // <- index
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 2); // <- compare value
|
|
useProducer(loadPrimitive.nthInputVariable(0), newInsn, 3); // <- memory
|
|
defineProducer(inPrimitive, newInsn, 0); // -> compare result
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_CmpI_I_MemDSI(Primitive& inPrimitive)
|
|
{
|
|
Uint32 constant = nthInputConstantUint32(inPrimitive, 1);
|
|
|
|
DataNode& loadPrimitive = inPrimitive.nthInput(0).getVariable();
|
|
MemDSIParameters parms(loadPrimitive);
|
|
assert(parms.scale <= 3); // eventually MemDSI will be limited to scale <=3
|
|
|
|
x86Instruction& newInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, iaCmpImm, constant, memDSIAddressingModes[parms.scale], parms.displacement, 3, 1);
|
|
useProducer(parms.baseProducer, newInsn, 0); // <- base
|
|
useProducer(parms.indexProducer, newInsn, 1); // <- index
|
|
useProducer(loadPrimitive.nthInputVariable(0), newInsn, 2); // <- memory
|
|
defineProducer(inPrimitive, newInsn, 0); // -> compare result
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_St_I_MemDSI(Primitive& inPrimitive)
|
|
{
|
|
MemDSIParameters parms(inPrimitive);
|
|
assert(parms.scale <= 3); // eventually MemDSI will be limited to scale <=3
|
|
|
|
InsnDoubleOpDir& newInsn =
|
|
*new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreI, parms.displacement, memDSIAddressingModes[parms.scale], atRegDirect, 4, 1);
|
|
useProducer(parms.baseProducer, newInsn, 0); // <- base
|
|
useProducer(parms.indexProducer, newInsn, 1); // <- index
|
|
useProducer(inPrimitive.nthInputVariable(2), newInsn, 2); // <- value reg
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 3); // <- memory edge
|
|
defineProducer(inPrimitive, newInsn, 0); // -> memory edge
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_Ld_I_MemDSI(Primitive& inPrimitive)
|
|
{
|
|
MemDSIParameters parms(inPrimitive);
|
|
assert(parms.scale <= 3); // eventually MemDSI will be limited to scale <=3
|
|
|
|
InsnDoubleOpDir& newInsn =
|
|
*new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, parms.displacement, memDSIAddressingModes[parms.scale], atRegDirect, 3, 1);
|
|
|
|
useProducer(parms.baseProducer, newInsn, 0); // <- base
|
|
useProducer(parms.indexProducer, newInsn, 1); // <- index
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 2); // <- memory edge
|
|
defineProducer(inPrimitive, newInsn, 0); // -> value
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
// Monitors
|
|
|
|
void x86Emitter::
|
|
emit_MonitorEnter(Primitive& inPrimitive)
|
|
{
|
|
// temporary, until we get syscall guard frames working on linux
|
|
#ifdef _WIN32
|
|
new(mPool) CallS_V(&inPrimitive, mPool, CallS_V::numberOfArguments(inPrimitive), true, *this, (void (*)())guardedsysMonitorEnter);
|
|
#else
|
|
new(mPool) CallS_V(&inPrimitive, mPool, CallS_V::numberOfArguments(inPrimitive), true, *this, (void (*)())sysMonitorEnter);
|
|
#endif
|
|
}
|
|
|
|
void x86Emitter::
|
|
emit_MonitorExit(Primitive& inPrimitive)
|
|
{
|
|
#ifdef _WIN32
|
|
new(mPool) CallS_V(&inPrimitive, mPool, CallS_V::numberOfArguments(inPrimitive), true, *this, (void (*)())guardedsysMonitorExit);
|
|
#else
|
|
new(mPool) CallS_V(&inPrimitive, mPool, CallS_V::numberOfArguments(inPrimitive), true, *this, (void (*)())sysMonitorExit);
|
|
#endif
|
|
}
|