toshok%hungry.com 9114c4a449 x86Win32ExceptionHandler.h => x86ExceptionHandler.h
git-svn-id: svn://10.0.0.236/trunk@54517 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-28 00:10:16 +00:00

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
}