fur%netscape.com 00b6a4565e A bunch of grunge work to reduce the amount of OS-dependent code in
ElectricalFire sources.  The end result eliminated nearly all of the
differences between FreeBSD and Linux in the source code.  It also
increased the amount of sharing between Win32 and unix code.

+   Renamed files and classes that were inappropriately named, i.e. the
    names started with 'x86Win32', but the code was for generic x86, not
    specific to Win32.

+   Eliminated several gratuitous duplicated files, e.g. x86Linux.s and
    x86FreeBSD.s were essentially identical.

+   Shared code that had been duplicated in x86Win32_Support.cpp,
    x86Linux_Support.cpp and x86FreeBSD_Support.cpp.  Created
    x86GenStub.cpp, which contains only XP code, to replace them all.


git-svn-id: svn://10.0.0.236/trunk@22373 18797224-902f-48f8-a5cc-f745e15eee43
1999-02-28 00:18:23 +00:00

1549 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// 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 "x86Win32ExceptionHandler.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
}