1623 lines
44 KiB
C++
1623 lines
44 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):
|
|
*/
|
|
// PPC601AppleMacOSEmitter.cp
|
|
//
|
|
// Scott M. Silver
|
|
// Peter Desantis
|
|
// Laurent Morichetti
|
|
//
|
|
// Subclass of InstructionEmitter which handles emitting for the ppc601
|
|
|
|
|
|
#include "PPC601AppleMacOSEmitter.h"
|
|
#include "PPC601AppleMacOS_Support.h"
|
|
#include "Instruction.h"
|
|
#include "ppc601-macos.nad.burg.h"
|
|
#include "ControlNodes.h"
|
|
#include "SysCalls.h"
|
|
#include "AssembledInstructions.h"
|
|
#include "PPCInstructions.h"
|
|
#include "PPCCalls.h"
|
|
|
|
// Use the PowerPC disassembler that comes with the mac if possible
|
|
#if defined(DEBUG) && defined(__MWERKS__)
|
|
#include <ConditionalMacros.h>
|
|
#if defined(GENERATINGPOWERPC) && GENERATINGPOWERPC
|
|
#define USING_MAC_PPC_DISASSEMBLER
|
|
#ifdef __TYPES__ // save old types
|
|
#define __OLD_TYPES__
|
|
#endif
|
|
#define __TYPES__
|
|
#include "Disassembler.h"
|
|
#define MAC_PPC_DISASSEMBLER_OPTIONS (Disassemble_PowerPC32|Disassemble_RsvBitsErr|Disassemble_FieldErr|Disassemble_Extended|Disassemble_BasicComm|Disassemble_CRBits|Disassemble_CRFltBits|Disassemble_BranchBO|Disassemble_TrapTO)
|
|
#ifndef __OLD_TYPES__
|
|
#undef __TYPES__
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
const Uint8 kR3Color = 0; // for return values <= 32 bits
|
|
const Uint8 kR4Color = 1; // for return values > 32 bits
|
|
|
|
const Uint8 kFR1Color = 0; // for return values <= 64 bits
|
|
|
|
const Uint8 kJitGlobalsColor = 29; // used for global values
|
|
const Uint8 kJitGlobalsRegister = 13;
|
|
const Uint8 kStackRegister = 13;
|
|
|
|
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊEmitter ¥
|
|
#endif
|
|
|
|
|
|
#define BINARY_PRIMITIVE_IX(inRuleKind, inOp) \
|
|
case inRuleKind: \
|
|
genArith_IX(inPrimitive, inOp); \
|
|
break;
|
|
|
|
#define BINARY_PRIMITIVE_ID(inRuleKind, inOp, inOpX) \
|
|
case inRuleKind: \
|
|
genArith_ID(inPrimitive, inOp, inOpX); \
|
|
break;
|
|
|
|
#define UNDEFINED_RULE(inRuleKind) \
|
|
case inRuleKind: \
|
|
assert(false); \
|
|
break;
|
|
|
|
#define BINARY_PRIMITIVE_SET(inRuleRoot, inOpX, inOpD) \
|
|
BINARY_PRIMITIVE_IX(inRuleRoot##_I, inOpX);
|
|
|
|
void PPCEmitter::
|
|
emitPrimitive(Primitive& inPrimitive, NamedRule inRule)
|
|
{
|
|
switch (inRule)
|
|
{
|
|
case emConst_I:
|
|
case emConst_A:
|
|
emit_Const_I(inPrimitive);
|
|
break;
|
|
case emConst_F:
|
|
emit_Const_F(inPrimitive);
|
|
break;
|
|
case emResult_I: case emResult_A:
|
|
emit_Result_I(inPrimitive);
|
|
break;
|
|
case emResult_F:
|
|
emit_Result_F(inPrimitive);
|
|
break;
|
|
case emIfLt: case emIfULt:
|
|
genBranch(inPrimitive, condLt);
|
|
break;
|
|
case emIfEq: case emIfUEq:
|
|
genBranch(inPrimitive, condEq);
|
|
break;
|
|
case emIfLe: case emIfULe:
|
|
genBranch(inPrimitive, condLe);
|
|
break;
|
|
case emIfGt: case emIfUGt:
|
|
genBranch(inPrimitive, condGt);
|
|
break;
|
|
case emIfLgt: case emIfNe:
|
|
genBranch(inPrimitive, condLgt);
|
|
break;
|
|
case emIfGe: case emIfUGe:
|
|
genBranch(inPrimitive, condGe);
|
|
break;
|
|
BINARY_PRIMITIVE_SET(emAnd, xfAnd, dfAndi);
|
|
BINARY_PRIMITIVE_SET(emOr, xfOr, dfOri);
|
|
BINARY_PRIMITIVE_SET(emXor, xfXor, dfXori);
|
|
BINARY_PRIMITIVE_SET(emAdd, xfAdd, dfAddi);
|
|
case emAdd_A: case emAddU_A:
|
|
genArith_IX(inPrimitive, xfAdd);
|
|
break;
|
|
// case emAddI_A:
|
|
// genArith_ID(inPrimitive, dfAddi, xfAdd);
|
|
// break;
|
|
// case emAddR_A:
|
|
// genArith_RD(inPrimitive, dfAddi, xfAdd, false);
|
|
// break;
|
|
// case emAddRU_A:
|
|
// genArith_RD(inPrimitive, dfAddi, xfAdd, true);
|
|
// break;
|
|
case emSub_I:
|
|
genArithReversed_IX(inPrimitive, xfSubf);
|
|
break;
|
|
/// case emSubR_I:
|
|
// emit_SubR(inPrimitive, false);
|
|
// break;
|
|
// case emSubAI_I:
|
|
// emit_SubI(inPrimitive);
|
|
// break;
|
|
/// case emSubAR_I:
|
|
// emit_SubR(inPrimitive, false);
|
|
// break;
|
|
// case emSub_A: case emSubU_A:
|
|
// genArithReversed_IX(inPrimitive, xfSubf);
|
|
// break;
|
|
// case emSubR_A:
|
|
// emit_SubR(inPrimitive, false);
|
|
// break;
|
|
// case emSubUR_A:
|
|
// emit_SubR(inPrimitive, true);
|
|
// break;
|
|
BINARY_PRIMITIVE_SET(emMul, xfMullw, dfMulli);
|
|
case emDiv_I:
|
|
emit_Div_I(inPrimitive);
|
|
break;
|
|
case emDivE_I:
|
|
emit_DivE_I(inPrimitive);
|
|
break;
|
|
// case emDivI_I:
|
|
// emit_DivI_I(inPrimitive);
|
|
// break;
|
|
// case emDivR_I:
|
|
// emit_DivR_I(inPrimitive);
|
|
// break;
|
|
// case emDivRE_I:
|
|
// emit_DivRE_I(inPrimitive);
|
|
// break;
|
|
case emDivU_I:
|
|
emit_DivU_I(inPrimitive);
|
|
break;
|
|
case emDivUE_I:
|
|
emit_DivUE_I(inPrimitive);
|
|
break;
|
|
// case emDivUI_I:
|
|
// emit_DivUI_I(inPrimitive);
|
|
// break;
|
|
// case emDivUR_I:
|
|
// emit_DivUR_I(inPrimitive);
|
|
// break;
|
|
// case emDivURE_I:
|
|
// emit_DivURE_I(inPrimitive);
|
|
// break;
|
|
case emModE_I:
|
|
emit_ModE_I(inPrimitive);
|
|
break;
|
|
case emShl_I:
|
|
{
|
|
Instruction& shiftLeft = *new(mPool) XFormXY(&inPrimitive, mPool, 2, 1, xfSlw, pfNil);
|
|
shiftLeft.standardUseDefine(*this);
|
|
}
|
|
break;
|
|
// case emShlI_I:
|
|
// emit_ShlI_I(inPrimitive);
|
|
// break;
|
|
//
|
|
case emChkNull:
|
|
{
|
|
TrapD& newInsn = *new(mPool) TrapD(&inPrimitive, mPool, condEq, false, 0);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
break;
|
|
// case emLimitR:
|
|
// emit_LimitR(inPrimitive);
|
|
// break;
|
|
case emLimit:
|
|
emit_Limit(inPrimitive, 0);
|
|
break;
|
|
case emLd_IRegisterIndirect: case emLd_ARegisterIndirect:
|
|
emit_Ld_IRegisterIndirect(inPrimitive);
|
|
break;
|
|
case emLd_I: case emLd_A:
|
|
{
|
|
LdD_& newInsn = *new(mPool) LdD_(&inPrimitive, mPool, dfLwz, 0);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
break;
|
|
case emSt_I:
|
|
{
|
|
StD& newInsn = *new(mPool) StD(&inPrimitive, mPool, dfStw, 0);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
break;
|
|
// case emStI_I:
|
|
// emit_StI_I(inPrimitive);
|
|
// break;
|
|
// case emStI_IRegisterIndirect:
|
|
// emit_StI_IRegisterIndirect(inPrimitive);
|
|
// break;
|
|
case emSt_IRegisterIndirect:
|
|
emit_St_IRegisterIndirect(inPrimitive);
|
|
break;
|
|
case emDynamicCall:
|
|
{
|
|
CallD_& newInsn = *new CallD_(&inPrimitive, mPool, CallD_::numberOfArguments(inPrimitive), CallD_::hasReturnValue(inPrimitive), *this);
|
|
}
|
|
break;
|
|
case emStaticCall:
|
|
{
|
|
Call_& newInsn = *new Call_(&inPrimitive, mPool, Call_::numberOfArguments(inPrimitive), Call_::hasReturnValue(inPrimitive), *this);
|
|
}
|
|
break;
|
|
case emSysCallEV:
|
|
{
|
|
CallS_V& newInsn = *new CallS_V(&inPrimitive, mPool, CallS_V::numberOfArguments(inPrimitive), CallS_V::hasReturnValue(inPrimitive), *this, PrimSysCall::cast(inPrimitive).sysCall.function);
|
|
}
|
|
break;
|
|
case emSysCallEC:
|
|
{
|
|
CallS_C& newInsn = *new CallS_C(&inPrimitive, mPool, CallS_C::numberOfArguments(inPrimitive), CallS_C::hasReturnValue(inPrimitive), *this, PrimSysCall::cast(inPrimitive).sysCall.function);
|
|
}
|
|
break;
|
|
case emSysCallE:
|
|
{
|
|
CallS_& newInsn = *new CallS_(&inPrimitive, mPool, CallS_::numberOfArguments(inPrimitive), CallS_::hasReturnValue(inPrimitive), *this, PrimSysCall::cast(inPrimitive).sysCall.function);
|
|
}
|
|
break;
|
|
case emCmp_I:
|
|
emit_Cmp_I(inPrimitive);
|
|
break;
|
|
// case emCmpI_I:
|
|
// emit_CmpI_I(inPrimitive);
|
|
// break;
|
|
case emFAdd_F:
|
|
{
|
|
Instruction& insn = sAFormInfos[afFadd].creatorFunction(inPrimitive, mPool, afFadd);
|
|
useProducer(inPrimitive.nthInputVariable(0), insn, 0, vrcFloatingPoint);
|
|
useProducer(inPrimitive.nthInputVariable(1), insn, 1, vrcFloatingPoint);
|
|
defineProducer(inPrimitive, insn, 0, vrcFloatingPoint);
|
|
}
|
|
break;
|
|
// case emFAddI_F:
|
|
// {
|
|
// VirtualRegister& contantVR = genLoadConstant_F(inPrimitive, inPrimitive.nthInputConstant(1).f);
|
|
// Instruction& insn = sAFormInfos[afFadd].creatorFunction(inPrimitive, mPool, afFadd);
|
|
// useProducer(inPrimitive.nthInputVariable(0), insn, 0, vrcFloatingPoint);
|
|
// useTemporaryVR(insn, contantVR, 1, vrcFloatingPoint);
|
|
// defineProducer(inPrimitive, insn, 0, vrcFloatingPoint);
|
|
// }
|
|
// break;
|
|
default:
|
|
//assert(false)
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_Const_I(Primitive& inPrimitive)
|
|
{
|
|
Int32 constant = (*static_cast<const PrimConst *>(&inPrimitive)).value.i;
|
|
|
|
// can't use genLoadConstant_I here because we need to assign the VR to this producer
|
|
// (and this producer could already have a VR assigned to it)
|
|
if ((constant <= 32767) && (constant >= -32768))
|
|
{
|
|
ArithIZeroInputD& lo16 = *new(mPool) ArithIZeroInputD(&inPrimitive, mPool, dfAddi, (Uint16) constant);
|
|
defineProducer(inPrimitive, lo16, 0);
|
|
}
|
|
else
|
|
{
|
|
// if we need to load a constant larger that 16 bits, then we use an addis, ori combo
|
|
// we need to make the input of the the ori depend on the output of the addis so that
|
|
// those instructions come in uninterrupted pairs (because we don't support defining half
|
|
// of a VirtualRegister)
|
|
ArithIZeroInputD& hi16 = *new(mPool) ArithIZeroInputD(&inPrimitive, mPool, dfAddis, (Uint16)((Uint32) constant >> 16));
|
|
VirtualRegister& constantVr = *defineProducer(inPrimitive, hi16, 0);
|
|
|
|
LogicalID& lo16 = *new(mPool) LogicalID(&inPrimitive, mPool, dfOri, (Uint16)((Uint32) constant));
|
|
useTemporaryVR(lo16, constantVr, 0);
|
|
redefineTemporary(lo16, constantVr, 0);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_Const_F(Primitive& inPrimitive)
|
|
{
|
|
Flt32 constant = (*static_cast<const PrimConst *>(&inPrimitive)).value.f;
|
|
|
|
Uint16 offset;
|
|
mAccumulatorTOC.addData(&constant, sizeof(constant), offset);
|
|
|
|
Instruction& ldConstant = *new(mPool) LdD_RTOC(&inPrimitive, mPool, dfLfs, offset);
|
|
defineProducer(inPrimitive, ldConstant, 0, vrcFloatingPoint);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_StI_I(Primitive& inPrimitive)
|
|
{
|
|
VirtualRegister& constantReg = genLoadConstant_I(inPrimitive, inPrimitive.nthInputConstant(2).i);
|
|
StD& storeInsn = *new(mPool) StD(&inPrimitive, mPool, dfStw, 0);
|
|
|
|
useTemporaryVR(storeInsn, constantReg, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), storeInsn, 0);
|
|
trespass("Not implemented yet");
|
|
//defineProducer(inPrimitive, storeInsn, 0);
|
|
//defineProducer(nthOutputProducer(inPrimitive, 1), storeInsn, 0);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_St_IRegisterIndirect(Primitive& inPrimitive)
|
|
{
|
|
Int16 offset;
|
|
|
|
// Need to get immediate arguement from producer's primitive
|
|
DataNode* addrSource = &inPrimitive.nthInput(1).getVariable();
|
|
|
|
if(!extractS16(PrimConst::cast(addrSource->nthInputVariable(1)).value, offset))
|
|
assert(false);
|
|
|
|
StD& storeInsn = *new(mPool) StD(&inPrimitive, mPool, dfStw, offset);
|
|
useProducer(inPrimitive.nthInputVariable(0), storeInsn, 0); // <- store
|
|
useProducer(addrSource->nthInputVariable(0), storeInsn, 1); // <- address base
|
|
useProducer(inPrimitive.nthInputVariable(2), storeInsn, 2); // <- value
|
|
defineProducer(inPrimitive, storeInsn, 0); // -> store
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_ShlI_I(Primitive& inPrimitive)
|
|
{
|
|
uint8 shiftBy;
|
|
|
|
extractU8(inPrimitive.nthInputConstant(1), shiftBy);
|
|
|
|
MFormInAOnly& newInsn = *new(mPool) MFormInAOnly(&inPrimitive, mPool, mfRlwinm, shiftBy, 0, 31 - shiftBy, pfNil); // slwi ra, rs, shiftBy
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_Div_I(Primitive& inPrimitive)
|
|
{
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivw, pfNil);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), divInsn, 1);
|
|
defineProducer(inPrimitive, divInsn, 0);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivE_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
emit_Div_I(inPrimitive);
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_DivI_I(Primitive& inPrimitive)
|
|
{
|
|
Value& immediate = inPrimitive.nthInputConstant(1);
|
|
|
|
if(isPowerOfTwo(immediate.i))
|
|
{
|
|
uint8 shiftBy = 31 - leadingZeros(immediate.i);
|
|
|
|
XInAOnly& shiftRight = *new(mPool) XInAOnly(&inPrimitive, mPool, xfSrawi, pfNil, shiftBy);
|
|
shiftRight.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& divisor = genLoadConstant_I(inPrimitive, immediate.i);
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivw, pfNil);
|
|
|
|
useTemporaryVR(divInsn, divisor, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
defineProducer(inPrimitive, divInsn, 0);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivR_I(Primitive& inPrimitive)
|
|
{
|
|
Value& immediate = inPrimitive.nthInputConstant(0); // remember it's reversed
|
|
|
|
if(isPowerOfTwo(immediate.i))
|
|
{
|
|
uint8 shiftBy = 31 - leadingZeros(immediate.i);
|
|
|
|
XInAOnly& shiftRight = *new(mPool) XInAOnly(&inPrimitive, mPool, xfSrawi, pfNil, shiftBy);
|
|
useProducer(inPrimitive.nthInputVariable(1), shiftRight, 0);
|
|
defineProducer(inPrimitive, shiftRight, 0);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& divisor = genLoadConstant_I(inPrimitive, immediate.i);
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivw, pfNil);
|
|
|
|
useTemporaryVR(divInsn, divisor, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), divInsn, 0);
|
|
defineProducer(inPrimitive, divInsn, 0);
|
|
}
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_DivRE_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
emit_DivR_I(inPrimitive);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivU_I(Primitive& inPrimitive)
|
|
{
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivwu, pfNil);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), divInsn, 0);
|
|
defineProducer(inPrimitive, divInsn, 0);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivUE_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
|
|
emit_DivU_I(inPrimitive);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivUI_I(Primitive& inPrimitive)
|
|
{
|
|
Value& immediate = inPrimitive.nthInputConstant(1);
|
|
|
|
if(isPowerOfTwo(immediate.i))
|
|
{
|
|
Uint8 shiftBy = 31 - leadingZeros(immediate.i);
|
|
|
|
MFormInAOnly& shiftRight = *new(mPool) MFormInAOnly(&inPrimitive, mPool, mfRlwinm, 32-shiftBy, shiftBy, 31, pfNil); // srwi ra, rs, shiftBy
|
|
shiftRight.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& divisor = genLoadConstant_I(inPrimitive, immediate.i);
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivwu, pfNil);
|
|
|
|
useTemporaryVR(divInsn, divisor, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
defineProducer(inPrimitive, divInsn, 0);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivUR_I(Primitive& inPrimitive)
|
|
{
|
|
Value& immediate = inPrimitive.nthInputConstant(0);
|
|
|
|
if(isPowerOfTwo(immediate.i))
|
|
{
|
|
uint8 shiftBy = 31 - leadingZeros(immediate.i);
|
|
|
|
MFormInAOnly& shiftRight = *new(mPool) MFormInAOnly(&inPrimitive, mPool, mfRlwinm, 32-shiftBy, shiftBy, 31, pfNil); // srwi ra, rs, shiftBy
|
|
useProducer(inPrimitive.nthInputVariable(1), shiftRight, 0);
|
|
defineProducer(inPrimitive.nthInputVariable(0), shiftRight, 0);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& divisor = genLoadConstant_I(inPrimitive, immediate.i);
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivwu, pfNil);
|
|
|
|
useTemporaryVR(divInsn, divisor, 1);
|
|
useProducer(inPrimitive.nthInputVariable(1), divInsn, 0);
|
|
defineProducer(inPrimitive, divInsn, 0);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_DivURE_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
|
|
emit_DivURE_I(inPrimitive);
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_Mod_I(Primitive& inPrimitive)
|
|
{
|
|
// divw rt, ta, rb # rt = (ra-R)/rb
|
|
// mullw rt, rt, rb # rt = ra-R
|
|
// subf rt, rt, rta # rt = R
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivw, pfNil);
|
|
useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), divInsn, 1);
|
|
VirtualRegister& tempVr = defineTemporary(divInsn, 0);
|
|
|
|
ArithX& mullInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfMullw, pfNil);
|
|
useProducer(inPrimitive.nthInputVariable(1), mullInsn, 1);
|
|
useTemporaryVR(mullInsn, tempVr, 0);
|
|
redefineTemporary(mullInsn, tempVr, 0);
|
|
|
|
ArithX& subInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfSubf, pfNil);
|
|
useTemporaryVR(subInsn, tempVr, 0);
|
|
useProducer(inPrimitive.nthInputVariable(0), subInsn, 1);
|
|
defineProducer(inPrimitive, subInsn, 0);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_ModE_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
emit_Mod_I(inPrimitive);
|
|
}
|
|
#if 0
|
|
|
|
void PPCEmitter::
|
|
emit_ModI_I(Primitive& inPrimitive)
|
|
{
|
|
genMod_I(inPrimitive);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_ModR_I(Primitive& inPrimitive)
|
|
{
|
|
genMod_I(inPrimitive);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_ModRE_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
genMod_I(inPrimitive);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_ModU_I(Primitive& inPrimitive)
|
|
{
|
|
genThrowIfDivisorZero(inPrimitive);
|
|
genMod_I(inPrimitive);
|
|
}
|
|
|
|
//ta = dividiend
|
|
//rb = divisor
|
|
|
|
void PPCEmitter::
|
|
genMod_I(Primitive& inPrimitive)
|
|
{
|
|
// FIX-ME? Could reduce register pressure here by
|
|
// folding the constant in the mullw to kill rb one instruction earlier
|
|
// divw rt, ta, rb # rt = (ra-R)/rb
|
|
// mullw rt, rt, rb # rt = ra-R
|
|
// subf rt, rt, rta # rt = R
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivw, pfNil);
|
|
VirtualRegister* dividendVr;
|
|
VirtualRegister* divisorVr;
|
|
|
|
if (inPrimitive.nthInputIsConstant(0))
|
|
dividendVr = &genLoadConstant_I(inPrimitive.nthInputConstant(0).i)
|
|
else
|
|
dividendVr = useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
|
|
if (inPrimitive.nthInputIsConstant(1))
|
|
divisorVr = &genLoadConstant_I(inPrimitive.nthInputConstant(1).i)
|
|
else
|
|
divisorVr = useProducer(inPrimitive.nthInputVariable(1), divInsn, 1);
|
|
|
|
VirtualRegister& tempVr = defineTemporary(divInsn, 0);
|
|
|
|
ArithX& mullInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfMullw, pfNil);
|
|
useTemporaryVR(mullInsn, *divisorVr, 1);
|
|
useTemporaryVR(mullInsn, tempVr, 0);
|
|
redefineTemporary(mullInsn, tempVr, 0);
|
|
|
|
ArithX& subInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfSubf, pfNil);
|
|
useTemporaryVR(subInsn, tempVr, 0);
|
|
useTemporaryVR(subInsn, *dividendVr, 1);
|
|
defineProducer(inPrimitive, subInsn, 0);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
genModU_I(Primitive& inPrimitive)
|
|
{
|
|
// FIX-ME? Could reduce register pressure here by
|
|
// folding the constant in the mullw to kill rb one instruction earlier
|
|
// divw rt, ta, rb # rt = (ra-R)/rb
|
|
// mullw rt, rt, rb # rt = ra-R
|
|
// subf rt, rt, rta # rt = R
|
|
ArithX& divInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfDivwu, pfNil);
|
|
VirtualRegister* dividendVr;
|
|
VirtualRegister* divisorVr;
|
|
|
|
if (inPrimitive.nthInputIsConstant(0))
|
|
dividendVr = &genLoadConstant_I(inPrimitive.nthInputConstant(0).i)
|
|
else
|
|
dividendVr = useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
|
|
|
|
if (inPrimitive.nthInputIsConstant(1))
|
|
divisorVr = &genLoadConstant_I(inPrimitive.nthInputConstant(1).i)
|
|
else
|
|
divisorVr = useProducer(inPrimitive.nthInputVariable(1), divInsn, 1);
|
|
|
|
VirtualRegister& tempVr = defineTemporary(divInsn, 0);
|
|
|
|
ArithX& mullInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfMullw, pfNil);
|
|
useTemporaryVR(mullInsn, *divisorVr, 1);
|
|
useTemporaryVR(mullInsn, tempVr, 0);
|
|
redefineTemporary(mullInsn, tempVr, 0);
|
|
|
|
ArithX& subInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfSubf, pfNil);
|
|
useTemporaryVR(subInsn, tempVr, 0);
|
|
useTemporaryVR(subInsn, *dividendVr, 1);
|
|
defineProducer(inPrimitive, subInsn, 0);
|
|
}
|
|
#endif
|
|
|
|
void PPCEmitter::
|
|
emit_Ld_IRegisterIndirect(Primitive& inPrimitive)
|
|
{
|
|
Int16 constant;
|
|
DataNode& immSource = inPrimitive.nthInput(1).getVariable(); // immediate arguement from producer's primitive
|
|
|
|
if(extractS16(immSource.nthInputConstant(1), constant))
|
|
{
|
|
LdD_& newInsn = *new(mPool) LdD_(&inPrimitive, mPool, dfLwz, constant);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 0); // M to poLd_I
|
|
useProducer(immSource.nthInputVariable(0), newInsn, 1); // Vint to poAdd_A
|
|
defineProducer(inPrimitive, newInsn, 0); // Vint from poLd_I
|
|
}
|
|
else
|
|
{
|
|
assert(false);
|
|
// emitPrimitive(immSource);
|
|
// emitPrimitive(inPrimitive);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_LimitR(Primitive& inPrimitive)
|
|
{
|
|
Int16 constant;
|
|
|
|
if (extractS16(inPrimitive.nthInputConstant(0), constant))
|
|
{
|
|
TrapD& newInsn = *new(mPool) TrapD(&inPrimitive, mPool, condLe, false, constant);
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0);
|
|
inPrimitive.setInstructionRoot(&newInsn);
|
|
}
|
|
else
|
|
{
|
|
// fix-me handle immediate values larger than the use of a single instruction allows
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_Limit(Primitive& inPrimitive, PPCInsnFlags inFlags)
|
|
{
|
|
TrapX& newInsn = *new(mPool) TrapX(&inPrimitive, mPool, condGe, false, inFlags);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_Cmp_I(Primitive& inPrimitive)
|
|
{
|
|
CmpIX& newInsn = *new(mPool) CmpIX(&inPrimitive, mPool, xfCmp, 0);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
emit_CmpI_I(Primitive& inPrimitive)
|
|
{
|
|
Int16 constant;
|
|
|
|
if (extractS16(inPrimitive.nthInputConstant(1), constant))
|
|
{
|
|
CmpID& newInsn = *new(mPool) CmpID(&inPrimitive, mPool, dfCmpi, constant);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& constantVr = genLoadConstant_I(inPrimitive, inPrimitive.nthInputConstant(1).i);
|
|
CmpIX& newInsn = *new(mPool) CmpIX(&inPrimitive, mPool, xfCmp, 0);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 0);
|
|
useTemporaryVR(newInsn, constantVr, 1);
|
|
defineProducer(inPrimitive, newInsn, 0);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_Result_I(Primitive& inPrimitive)
|
|
{
|
|
VirtualRegister* returnVr;
|
|
|
|
if (inPrimitive.nthInputIsConstant(0))
|
|
{
|
|
// if the result is a constant load it into a register
|
|
returnVr = &genLoadConstant_I(inPrimitive, inPrimitive.nthInputConstant(0).i);
|
|
}
|
|
else
|
|
{
|
|
// otherwise create a buffer copy instruction between the result
|
|
// and the precolored register
|
|
Copy_I& copyInsn = *new(mPool) Copy_I(&inPrimitive, mPool);
|
|
|
|
returnVr = &defineTemporary(copyInsn, 0);
|
|
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0);
|
|
}
|
|
|
|
// integer results (and _A go in r3)
|
|
returnVr->preColorRegister(kR3Color);
|
|
|
|
// create a special instruction for the RegisterAllocator which says this result
|
|
// is used elsewhere (but not in this body of code).
|
|
InsnExternalUse& externalUse = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
|
|
useTemporaryVR(externalUse, *returnVr, 0);
|
|
inPrimitive.setInstructionRoot(&externalUse);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_Result_F(Primitive& inPrimitive)
|
|
{
|
|
VirtualRegister* returnVr;
|
|
|
|
if (inPrimitive.nthInputIsConstant(0))
|
|
{
|
|
// if the result is a constant load it into a register
|
|
returnVr = &genLoadConstant_F(inPrimitive, inPrimitive.nthInputConstant(0).f);
|
|
}
|
|
else
|
|
{
|
|
// otherwise create a buffer copy instruction between the result
|
|
// and the precolored register
|
|
XInBOnly& copyInsn = *new(mPool) XInBOnly(&inPrimitive, mPool, xfFmr, pfNil);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0, vrcFloatingPoint);
|
|
returnVr = &defineTemporary(copyInsn, 0, vrcFloatingPoint);
|
|
}
|
|
|
|
// integer results (and _A go in r3)
|
|
returnVr->preColorRegister(1);
|
|
|
|
// create a special instruction for the RegisterAllocator which says this result
|
|
// is used elsewhere (but not in this body of code).
|
|
InsnExternalUse& externalUse = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
|
|
useTemporaryVR(externalUse, *returnVr, 0, vrcFloatingPoint);
|
|
inPrimitive.setInstructionRoot(&externalUse);
|
|
}
|
|
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ Utilities ¥
|
|
#endif
|
|
|
|
void PPCEmitter::
|
|
genLoadIZero(Primitive& inPrimitive, PPCInsnFlags /*inFlags*/)
|
|
{
|
|
LdD_& newInsn = *new(mPool) LdD_(&inPrimitive, mPool, dfLwz, 0);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
|
|
void PPCEmitter::
|
|
genBranch(Primitive& inPrimitive, Condition2 cond)
|
|
{
|
|
ControlNode& controlIf = *inPrimitive.getContainer();
|
|
BranchCB& newInsn = *new(mPool) BranchCB(&inPrimitive, mPool, controlIf.getTrueSuccessor().getTarget(), cond, false, false);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
// need to do an add
|
|
// with a negated constant
|
|
void PPCEmitter::
|
|
emit_SubI(Primitive& inPrimitive)
|
|
{
|
|
Int16 constant;
|
|
|
|
// perform an addi with -constant if we're in range
|
|
if (extractS16(inPrimitive.nthInputConstant(1), constant))
|
|
{
|
|
ArithID& newInsn = *new(mPool) ArithID(&inPrimitive, mPool, dfAddi, -constant);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
// otherwise load the constant, and do a subf
|
|
VirtualRegister& constantReg = genLoadConstant_I(inPrimitive, inPrimitive.nthInputConstant(1).i);
|
|
|
|
ArithX& opInsn = *new(mPool) ArithX(&inPrimitive, mPool, xfSubf, pfNil);
|
|
|
|
useTemporaryVR(opInsn, constantReg, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), opInsn, 0);
|
|
defineProducer(inPrimitive, opInsn, 0);
|
|
}
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emit_SubR(Primitive& inPrimitive, bool inUnsigned)
|
|
{
|
|
// first negate the Vint edge
|
|
Instruction& negate = *new(mPool) XInAOnly(&inPrimitive, mPool, xfNeg, pfNil, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), negate, 0);
|
|
defineProducer(inPrimitive, negate, 0);
|
|
|
|
// then perform the appropriate add
|
|
genArith_RD(inPrimitive, dfAddi, xfAdd, inUnsigned);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
genArith_ID(Primitive& inPrimitive, DFormKind inKind, XFormKind inXKind)
|
|
{
|
|
Int16 constant;
|
|
|
|
if (extractS16(inPrimitive.nthInputConstant(1), constant))
|
|
{
|
|
ArithID& newInsn = *new(mPool) ArithID(&inPrimitive, mPool, inKind, constant);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& constantReg = genLoadConstant_I(inPrimitive, inPrimitive.nthInputConstant(1).i);
|
|
|
|
ArithX& opInsn = *new(mPool) ArithX(&inPrimitive, mPool, inXKind, pfNil);
|
|
|
|
useTemporaryVR(opInsn, constantReg, 0);
|
|
useProducer(inPrimitive.nthInputVariable(0), opInsn, 1);
|
|
defineProducer(inPrimitive, opInsn, 0);
|
|
}
|
|
}
|
|
|
|
// this is when the constant is in the first position, not in the second
|
|
void PPCEmitter::
|
|
genArith_RD(Primitive& inPrimitive, DFormKind inKind, XFormKind inXKind, bool inIsUnsigned)
|
|
{
|
|
Int16 constant;
|
|
|
|
// use a normal D form Arithmetic if the value fits in a signed word, or
|
|
// it's unsigned and the constant is > 0 if it were treated as signed
|
|
if (extractS16(inPrimitive.nthInputConstant(0), constant) && ((!inIsUnsigned) || (inIsUnsigned && constant >= 0)))
|
|
{
|
|
ArithID& newInsn = *new(mPool) ArithID(&inPrimitive, mPool, inKind, constant);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0);
|
|
defineProducer(inPrimitive, newInsn, 0);
|
|
}
|
|
else
|
|
{
|
|
VirtualRegister& constantReg = genLoadConstant_I(inPrimitive, inPrimitive.nthInputConstant(0).i);
|
|
|
|
ArithX& opInsn = *new(mPool) ArithX(&inPrimitive, mPool, inXKind, pfNil);
|
|
|
|
useTemporaryVR(opInsn, constantReg, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), opInsn, 1);
|
|
defineProducer(inPrimitive, opInsn, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PPCEmitter::
|
|
genArith_IX(Primitive& inPrimitive, XFormKind inKind)
|
|
{
|
|
ArithX& newInsn = *new(mPool) ArithX(&inPrimitive, mPool, inKind, pfNil);
|
|
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
// this is for reversed operands in the native instruction
|
|
void PPCEmitter::
|
|
genArithReversed_IX(Primitive& inPrimitive, XFormKind inKind)
|
|
{
|
|
ArithX& newInsn = *new(mPool) ArithX(&inPrimitive, mPool, inKind, pfNil);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(1), newInsn, 0);
|
|
useProducer(inPrimitive.nthInputVariable(0), newInsn, 1);
|
|
defineProducer(inPrimitive, newInsn, 0);
|
|
}
|
|
|
|
|
|
VirtualRegister& PPCEmitter::
|
|
genLoadConstant_I(DataNode& inPrimitive, Int32 inConstant)
|
|
{
|
|
VirtualRegister* vr;
|
|
|
|
if ((inConstant <= 32767) && (inConstant >= -32768))
|
|
{
|
|
ArithIZeroInputD& lo16 = *new(mPool) ArithIZeroInputD(&inPrimitive, mPool, dfAddi, inConstant);
|
|
vr = &defineTemporary(lo16, 0);
|
|
}
|
|
else
|
|
{
|
|
// if we need to load a constant larger that 16 bits, then we use an addis, ori combo
|
|
ArithIZeroInputD& hi16 = *new(mPool) ArithIZeroInputD(&inPrimitive, mPool, dfAddis, (Uint16)(((Uint32) inConstant) >> 16));
|
|
VirtualRegister& constantVr = defineTemporary(hi16, 0);
|
|
|
|
LogicalID& lo16 = *new(mPool) LogicalID(&inPrimitive, mPool, dfOri, (Uint16)((Uint32) inConstant));
|
|
useTemporaryVR(lo16, constantVr, 0);
|
|
redefineTemporary(lo16, constantVr, 0);
|
|
|
|
vr = &constantVr;
|
|
}
|
|
|
|
return (*vr);
|
|
}
|
|
|
|
|
|
VirtualRegister& PPCEmitter::
|
|
genLoadConstant_F(DataNode& inPrimitive, Flt32 inConstant)
|
|
{
|
|
Uint16 offset;
|
|
void *d = mAccumulatorTOC.addData(&inConstant, sizeof(inConstant), offset);
|
|
assert(d);
|
|
|
|
Instruction& ldConstant = *new(mPool) LdD_RTOC(&inPrimitive, mPool, dfLfs, offset);
|
|
return (defineTemporary(ldConstant, 0, vrcFloatingPoint));
|
|
}
|
|
|
|
void PPCEmitter::
|
|
genThrowIfDivisorZero(Primitive& inPrimitive)
|
|
{
|
|
// Check the divisor != 0
|
|
TrapD& trapInsn = *new(mPool) TrapD(&inPrimitive, mPool, condEq, false, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), trapInsn, 0);
|
|
inPrimitive.setInstructionRoot(&trapInsn);
|
|
}
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊFormatting Support ¥
|
|
#endif
|
|
|
|
Instruction& PPCEmitter::
|
|
emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget)
|
|
{
|
|
BranchI& newInsn = *new(mPool) BranchI(&inDataNode, mPool, inTarget, false, false);
|
|
|
|
return (newInsn);
|
|
}
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊRegisterAllocator Support ¥
|
|
#endif
|
|
|
|
bool PPCEmitter::
|
|
emitCopyAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& fromVr, VirtualRegister& toVr)
|
|
{
|
|
ArithID& newInsn = *new(mPool) ArithID(&inDataNode, mPool, dfAddi, 0);
|
|
|
|
newInsn.addUse(0, fromVr);
|
|
newInsn.addDefine(0, toVr);
|
|
#ifdef DEBUG
|
|
toVr.setDefiningInstruction(newInsn);
|
|
#endif
|
|
newInsn.insertAfter(*where);
|
|
return false;
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emitStoreAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& storedReg, VirtualRegister& stackReg)
|
|
{
|
|
StD_SpillRegister& newInsn = *new(mPool) StD_SpillRegister(&inDataNode, mPool, stackReg, storedReg);
|
|
|
|
newInsn.insertAfter(*where);
|
|
}
|
|
|
|
void PPCEmitter::
|
|
emitLoadAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& loadedReg, VirtualRegister& stackReg)
|
|
{
|
|
LdD_SpillRegister& newInsn = *new(mPool) LdD_SpillRegister(&inDataNode, mPool, stackReg, loadedReg);
|
|
#ifdef DEBUG
|
|
loadedReg.setDefiningInstruction(newInsn);
|
|
#endif
|
|
newInsn.insertAfter(*where);
|
|
}
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊDebug Support ¥
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
void*
|
|
disassemble1(LogModuleObject &f, void* inFrom)
|
|
{
|
|
#ifdef USING_MAC_PPC_DISASSEMBLER
|
|
char mnemonic[100];
|
|
char operand[100];
|
|
char comment[100];
|
|
|
|
ppcDisassembler((unsigned long *)inFrom, 0, MAC_PPC_DISASSEMBLER_OPTIONS, mnemonic, operand, comment, NULL, NULL);
|
|
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%p: %-10s %-40s %-40s\n", inFrom, mnemonic, operand, comment));
|
|
|
|
return ((char*) inFrom + 4);
|
|
#else
|
|
f;
|
|
inFrom = NULL;
|
|
return NULL;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊLinkage Support ¥
|
|
#endif
|
|
|
|
void PPCEmitter::
|
|
emitArguments(ControlNode::BeginExtra& inBeginNode)
|
|
{
|
|
Uint16 curParamWords; // number of words of argument space used
|
|
Uint16 curFloatingPointArg; // number of floating point arguments
|
|
|
|
if (inBeginNode.nArguments == 0)
|
|
return;
|
|
|
|
InsnExternalDefine& defineInsn = *new(mPool) InsnExternalDefine(&inBeginNode[0], mPool, inBeginNode.nArguments * 2);
|
|
|
|
Uint8 curArgIdx; // current index into the arguments in ControlNode::BeginExtra
|
|
|
|
curParamWords = 0;
|
|
curFloatingPointArg = 1;
|
|
for (curArgIdx = 0; curArgIdx < inBeginNode.nArguments && curParamWords < 8; curArgIdx++)
|
|
{
|
|
PrimArg& curArg = inBeginNode[curArgIdx];
|
|
|
|
switch (curArg.getOperation())
|
|
{
|
|
case poArg_I:
|
|
case poArg_A:
|
|
{
|
|
if (curArg.hasConsumers())
|
|
{
|
|
Copy_I& copyInsn = *new(mPool) Copy_I(&curArg, mPool);
|
|
|
|
// hook up this vr to the external define FIX-ME
|
|
VirtualRegister& inputVr = defineTemporary(defineInsn, curArgIdx);
|
|
inputVr.preColorRegister(curParamWords);
|
|
|
|
// emit the copy
|
|
useTemporaryVR(copyInsn, inputVr, 0);
|
|
defineProducer(curArg, copyInsn, 0);
|
|
}
|
|
curParamWords++;
|
|
break;
|
|
}
|
|
case poArg_L:
|
|
{
|
|
assert(false);
|
|
if (curParamWords < 6)
|
|
{
|
|
Copy_I& copyInsn = *new(mPool) Copy_I(&curArg, mPool);
|
|
|
|
// hook up this vr to the external define FIX-ME
|
|
VirtualRegister& inputVr = defineTemporary(defineInsn, curArgIdx);
|
|
|
|
useTemporaryVR(copyInsn, inputVr, 0);
|
|
defineProducer(curArg, copyInsn, 0);
|
|
|
|
//inputVr.preColorRegister(curParamWords);
|
|
//inputVr.preColorRegister(curParamWords);
|
|
}
|
|
else if (curParamWords < 7)
|
|
{
|
|
// make the external define create this argument
|
|
VirtualRegister& inputVr = defineTemporary(defineInsn, curArgIdx); // specify 32bit fixed point register
|
|
inputVr.preColorRegister(6);
|
|
|
|
// copy the hiword argument in r10 (color=6) to a new vr
|
|
Copy_I& copyInsn = *new(mPool) Copy_I(&curArg, mPool);
|
|
useTemporaryVR(copyInsn, inputVr, 0);
|
|
|
|
VirtualRegister& copyVr64 = mVRAllocator.newVirtualRegister(); // FIX-ME want to specify a "64" bit vr
|
|
defineProducerWithExistingVirtualRegister(copyVr64, curArg, copyInsn, 0);
|
|
|
|
// copy the loword argument from the appropriate stackslot to a new vr
|
|
LdD_FixedSource<kStackRegister>& loadParam = *new(mPool) LdD_FixedSource<kStackRegister>(&curArg, mPool, dfLwz, 24 + 32);
|
|
|
|
// fix-me add use or change to special stack relative load
|
|
defineProducer(curArg, loadParam, 0); // specify loword of 32 bit register
|
|
}
|
|
curParamWords+=2;
|
|
break;
|
|
}
|
|
case poArg_F:
|
|
{
|
|
XInBOnly& copyInsn = *new(mPool) XInBOnly(&curArg, mPool, xfFmr, pfNil);
|
|
|
|
// emit the copy
|
|
// hook up this vr to the external define
|
|
VirtualRegister& inputVr = defineTemporary(defineInsn, curArgIdx, vrcFloatingPoint);
|
|
inputVr.preColorRegister(curFloatingPointArg);
|
|
|
|
useTemporaryVR(copyInsn, inputVr, 0, vrcFloatingPoint);
|
|
defineProducer(curArg, copyInsn, 0, vrcFloatingPoint);
|
|
|
|
curParamWords++;
|
|
curFloatingPointArg++;
|
|
break;
|
|
}
|
|
case poArg_D:
|
|
assert(false);
|
|
break;
|
|
|
|
case poArg_M:
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
// do appropriate loads for each argument
|
|
Uint8 stackArgIdx;
|
|
for (stackArgIdx = curArgIdx; stackArgIdx < inBeginNode.nArguments; stackArgIdx++)
|
|
{
|
|
PrimArg& curArg = inBeginNode[stackArgIdx];
|
|
|
|
switch (curArg.getOperation())
|
|
{
|
|
case poArg_I:
|
|
case poArg_A:
|
|
{
|
|
if (curArg.hasConsumers())
|
|
{
|
|
LdD_FixedSource<kStackRegister>& loadParam = *new(mPool) LdD_FixedSource<kStackRegister>(&curArg, mPool, dfLwz, 24 + curParamWords * 4);
|
|
|
|
useTemporaryOrder(loadParam, defineTemporaryOrder(defineInsn, stackArgIdx), 0);
|
|
defineProducer(curArg, loadParam, 0);
|
|
}
|
|
curParamWords++;
|
|
break;
|
|
}
|
|
case poArg_L:
|
|
assert(false);
|
|
case poArg_F:
|
|
{
|
|
#if 0
|
|
LoadSP& loadParam = *new(mPool) LoadSP(&curArg, mPool, 24 + curParamWords * 4, dfLfs);
|
|
|
|
defineProducer(curArg, loadParam, 0);
|
|
#endif
|
|
curParamWords++;
|
|
break;
|
|
}
|
|
case poArg_D:
|
|
assert(false);
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
// continue counting from before
|
|
// make all the rest of the defines as type none
|
|
for (;curArgIdx < inBeginNode.nArguments * 2; curArgIdx++)
|
|
defineInsn.getInstructionDefineBegin()[curArgIdx].kind = udNone;
|
|
|
|
#if 0
|
|
MacDebugger& macDebugger = *new(mPool) MacDebugger(&inBeginNode.initialMemory, *this);
|
|
inBeginNode.initialMemory.setInstructionRoot(&macDebugger);
|
|
#endif
|
|
}
|
|
|
|
|
|
const Uint32 upper16 = 0xffff0000;
|
|
const Uint32 lower16 = 0x0000ffff;
|
|
|
|
|
|
void PPCFormatter::
|
|
calculatePrologEpilog(Method& /*inMethod*/, Uint32& outPrologSize, Uint32& outEpilogSize)
|
|
{
|
|
Uint8 usedNonVolatileGPR = 10; // mVRAllocator.nUsedCalleeSavedRegisters;
|
|
Uint8 usedNonVolatileFPR = 0;
|
|
Uint32 localsWords = 0; // localSize_words
|
|
const Uint32 kLinkAreaWords = 2;
|
|
Uint32 totalRegisterWords;
|
|
|
|
assert(usedNonVolatileGPR <= 14);
|
|
assert(usedNonVolatileFPR <= 13);
|
|
|
|
mSaveGPRwords = usedNonVolatileGPR;
|
|
mSaveFPRwords = usedNonVolatileFPR * 2; // 2 words per FPR
|
|
|
|
// total amount of space needed to save non-volatile registers
|
|
totalRegisterWords = mSaveGPRwords + mSaveFPRwords;
|
|
if(totalRegisterWords < 8)
|
|
totalRegisterWords = 8;
|
|
|
|
// figure total size of frame
|
|
mFrameSizeWords = mEmitter.mMaxArgWords + kLinkAreaWords + localsWords + totalRegisterWords;
|
|
mFrameSizeWords = (mFrameSizeWords + 3 & ~3); // align to 4 byte boundary
|
|
|
|
Uint32 prologSize_words;
|
|
Uint32 epilogSize_words;
|
|
|
|
// Number of instructions
|
|
if((mFrameSizeWords * 4) > 32768) // We need 3 instructions to create the stack frame
|
|
{
|
|
// Prolog needs 4 instruction to save CR and LR
|
|
// and 1 instruction to save each FPR and GPR
|
|
// and 3 instructions to create the stack frame
|
|
prologSize_words = 7 + usedNonVolatileFPR + usedNonVolatileGPR;
|
|
|
|
// Epilog needs 4 instruction to restore CR and LR
|
|
// and 1 instruction to restore each FPR and GPR
|
|
// and 3 instruction to restore the stack frame
|
|
// and 1 instruction to return (branch to lr)
|
|
epilogSize_words = prologSize_words + 1;
|
|
}
|
|
else
|
|
{
|
|
// We need 1 instruction to create the stack frame
|
|
// Prolog needs 4 instruction to save CR and LR
|
|
// and 1 instruction to save each FPR and GPR
|
|
// and 1 instruction to create the stack frame
|
|
prologSize_words = 1 + 2 + /*2*/ + usedNonVolatileFPR + usedNonVolatileGPR;
|
|
|
|
// Epilog needs 4 instruction to restore CR and LR
|
|
// and 1 instruction to restore each FPR and GPR
|
|
// and 1 instruction to restore the stack frame
|
|
// and 1 instruction to return (branch to lr)
|
|
epilogSize_words = prologSize_words + 1;
|
|
}
|
|
|
|
// now convert from words to bytes
|
|
outPrologSize = prologSize_words * 4;
|
|
outEpilogSize = epilogSize_words * 4;
|
|
}
|
|
|
|
|
|
void PPCFormatter::
|
|
formatPrologToMemory(void* inWhere)
|
|
{
|
|
Uint32* nextInstruction = (Uint32*)inWhere;
|
|
|
|
#if 0
|
|
/*
|
|
Write instructions to save CR
|
|
mfcr r0
|
|
stw r0, 4(r1)
|
|
*/
|
|
*nextInstruction++ = mfcrR0;
|
|
*nextInstruction++ = stwR04R1;
|
|
#endif
|
|
|
|
/*
|
|
Write instructions to save LR
|
|
mflr r0
|
|
stw r0, 8(r1)
|
|
*/
|
|
*nextInstruction++ = mflrR0;
|
|
*nextInstruction++ = stwR08R1;
|
|
|
|
/*
|
|
Save non-volatile FPRs
|
|
non volatile floating point registers are in the range fr14 - fr31
|
|
the saved block of non-volatile registers must start at fr31 and move up to fr 14
|
|
|
|
for(i = 0; i < #FPR to be saved; i++)
|
|
stfd fr(31-x), (-8 * (i+1))(r1)
|
|
*/
|
|
Uint16 i;
|
|
|
|
for(i = 0; i < (mSaveFPRwords/2); i++)
|
|
{
|
|
Uint32 fpr = 31-i;
|
|
fpr = fpr<<21;
|
|
Int32 off = (-8 * (i+1));
|
|
Uint32 offset = off & lower16;
|
|
|
|
Uint32 stfd = stfd_FR_offR1 | fpr | offset;
|
|
|
|
*nextInstruction++ = stfd;
|
|
}
|
|
|
|
/*
|
|
Save non-volatile GPRs
|
|
non volatile general purpose registers are in the range r13 - r31
|
|
the saved block of non-volatile registers must start at r31 and move up to fr 13
|
|
|
|
for(i = 0; i < #GPR to be saved; i++)
|
|
stw r(31-x), (-4 * (i+1)) - (4 * fprSize_words)) (r1)
|
|
*/
|
|
for(i = 0; i < (mSaveGPRwords); i++)
|
|
{
|
|
Uint32 gpr = 31-i;
|
|
gpr = gpr<<21;
|
|
Int32 off = (-4 * (i+1)) - (4 * mSaveFPRwords);
|
|
Uint32 offset = off & lower16;
|
|
|
|
Uint32 stw = stw_R_offR1 | gpr | offset;
|
|
|
|
*nextInstruction++ = stw;
|
|
}
|
|
|
|
/*
|
|
Create stack frame
|
|
|
|
if(frameSize_bytes > 32768)
|
|
lis r12, upper 16-bits of -frameSize_bytes
|
|
ori r12, lower 16-bits of -frameSize_bytes
|
|
stwuz r1, r1, r12stwu r1, -frameSize_bytes(r1)
|
|
else
|
|
stwu r1, -frameSize_bytes(r1)
|
|
*/
|
|
|
|
Int32 frameSize_bytes = -4*mFrameSizeWords;
|
|
if(frameSize_bytes < -32768)
|
|
{
|
|
|
|
Uint32 sfUpper = upper16 & frameSize_bytes;
|
|
sfUpper = sfUpper>>16;
|
|
Uint32 sfLower = lower16 & frameSize_bytes;
|
|
|
|
uint lis = lisR12_imm | sfUpper;
|
|
uint ori = oriR12R12_imm | sfLower;
|
|
|
|
*nextInstruction++ = lis;
|
|
*nextInstruction++ = ori;
|
|
*nextInstruction = stwuxR1R1R12 ;
|
|
|
|
} else {
|
|
Uint32 offset = frameSize_bytes & lower16;
|
|
uint stwv = stwuR1_offR1 | offset;
|
|
*nextInstruction = stwv;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
nextInstruction++;
|
|
Uint32 numberInstructions = nextInstruction - (Uint32*)inWhere;
|
|
// assert((numberInstructions * 4) == mPrologSize_bytes); FIX-ME
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void PPCFormatter::
|
|
formatEpilogToMemory(void* inWhere)
|
|
{
|
|
Uint32* nextInstruction = (Uint32*)inWhere;
|
|
|
|
/*
|
|
Return to parent's stack frame
|
|
|
|
if(frameSize_bytes > 32768)
|
|
lis r12, upper 16-bits of frameSize_bytes
|
|
ori r12, lower 16-bits of frameSize_bytes
|
|
addi r1, r1, r12
|
|
else
|
|
addi r1, r1, frameSize_bytes
|
|
*/
|
|
|
|
const Uint32 frameSize_bytes = 4*mFrameSizeWords;
|
|
if(frameSize_bytes > 32768)
|
|
{
|
|
Uint32 sfUpper = upper16 & frameSize_bytes;
|
|
sfUpper = sfUpper>>16;
|
|
Uint32 sfLower = lower16 & frameSize_bytes;
|
|
|
|
uint lis = lisR12_imm | sfUpper;
|
|
uint ori = oriR12R12_imm | sfLower;
|
|
|
|
*nextInstruction++ = lis;
|
|
*nextInstruction++ = ori;
|
|
*nextInstruction++ = addR1R1R12;
|
|
}
|
|
else
|
|
{
|
|
Uint32 offset = lower16 & frameSize_bytes;
|
|
Uint32 addi = addiR1R1_imm | offset;
|
|
*nextInstruction++ = addi;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
restore CR
|
|
lwz r0, 4(r1)
|
|
mtcr r0
|
|
*/
|
|
*nextInstruction++ = lwzR04R1;
|
|
*nextInstruction++ = mtcrR0;
|
|
#endif
|
|
|
|
/*
|
|
restore LR
|
|
lwz r0, 8(r1)
|
|
mtlr r0
|
|
*/
|
|
*nextInstruction++ = lwzR08R1;
|
|
*nextInstruction++ = kMtlrR0;
|
|
|
|
/*
|
|
Restore non-volatile FPRs
|
|
for(i = 0; i < #FPR to be saved; i++)
|
|
lfd fr(31-x), (-8 * (i+1))(r1)
|
|
*/
|
|
Uint16 i;
|
|
|
|
for(i = 0; i < (mSaveFPRwords/2); i++)
|
|
{
|
|
Uint32 fpr = 31-i;
|
|
fpr = fpr<<21;
|
|
Int32 off = (-8 * (i+1));
|
|
Uint32 offset = off & lower16;
|
|
|
|
Uint32 lfd = lfd_FR_offR1 | fpr | offset;
|
|
|
|
*nextInstruction++ = lfd;
|
|
}
|
|
|
|
|
|
/*
|
|
Save non-volatile GPRs
|
|
for(i = 0; i < #GPR to be saved; i++)
|
|
lwz r(31-x), (-4 * (i+1)) - (4 * fprSize_words)) (r1)
|
|
*/
|
|
for(i = 0; i < (mSaveGPRwords); i++)
|
|
{
|
|
Uint32 gpr = 31-i;
|
|
gpr = gpr<<21;
|
|
Int32 off = (-4 * (i+1)) - (4 * mSaveFPRwords);
|
|
Uint32 offset = off & lower16;
|
|
|
|
Uint32 lwz = lwz_R_offR1 | gpr | offset;
|
|
|
|
*nextInstruction++ = lwz;
|
|
}
|
|
|
|
*nextInstruction = kBlr;
|
|
|
|
#ifdef DEBUG
|
|
nextInstruction++;
|
|
Uint32 numberInstructions = nextInstruction - (Uint32*)inWhere;
|
|
//assert((numberInstructions * 4) == mEpilogSize_bytes); // FIX-ME
|
|
#endif
|
|
}
|
|
|
|
#ifdef XP_MAC
|
|
#include "StringUtils.h"
|
|
|
|
class PPCTraceInfo
|
|
{
|
|
// a trace back table is a PPCTraceInfo
|
|
// aligned on a 4 byte boundary
|
|
public:
|
|
PPCTraceInfo(const char* inSymbol) :
|
|
symbol(inSymbol)
|
|
{
|
|
symbolLen = PL_strlen(symbol);
|
|
magic[0] = 0;
|
|
magic[1] = 0x00092040;
|
|
magic[2] = 0;
|
|
}
|
|
|
|
Uint32 magic[3]; // some flags and other unknown stuff
|
|
Uint32 functionLen; // length of function in bytes
|
|
Uint16 symbolLen; // length of following symbol
|
|
TemporaryStringCopy symbol; // symbol to write out
|
|
|
|
size_t
|
|
getFormattedSize()
|
|
{
|
|
size_t size = offsetof(PPCTraceInfo, symbol) + symbolLen;
|
|
|
|
// align 4
|
|
return ((size + 3) & ~3);
|
|
}
|
|
|
|
void
|
|
formatToMemory(void* inStart, Uint32 inFunctionLength)
|
|
{
|
|
Uint32 x[] = {0, 0x00092041, 0x80030000, 0x00000078, 0x00202E5F, 0x5F63745F, 0x5F313954, 0x656D706F, 0x72617279, 0x53747269, 0x6E67436F, 0x70794650, 0x43630000};
|
|
|
|
unsigned char* output = static_cast<unsigned char*>(inStart);
|
|
char *cp;
|
|
|
|
for (cp = symbol; *cp; cp++)
|
|
{
|
|
if (!(('A' <= *cp && *cp <= 'Z') || ('a' <= *cp && *cp <= 'z')))
|
|
*cp = 'x';
|
|
}
|
|
|
|
functionLen = inFunctionLength;
|
|
output += offsetof(PPCTraceInfo, symbol);
|
|
memcpy(output, symbol, symbolLen);
|
|
|
|
symbolLen = (symbolLen + 1) & ~1;
|
|
output -= offsetof(PPCTraceInfo, symbol);
|
|
memcpy(output, &magic[0], offsetof(PPCTraceInfo, symbol));
|
|
}
|
|
};
|
|
|
|
|
|
#endif // XP_MAC
|
|
|
|
#include "FieldOrMethod.h"
|
|
#include "NativeFormatter.h"
|
|
|
|
void PPCFormatter::
|
|
beginFormatting(const FormattedCodeInfo& inInfo)
|
|
{
|
|
Int16 offsetInRealTOC;
|
|
|
|
// determine offset we need to add to the offsets into the accumulator toc
|
|
mRealTOC = &acquireTOC(mEmitter.mAccumulatorTOC.getNext() - mEmitter.mAccumulatorTOC.mBegin);
|
|
|
|
void *d = mRealTOC->addData(mEmitter.mAccumulatorTOC.mBegin, mEmitter.mAccumulatorTOC.getNext() - mEmitter.mAccumulatorTOC.mBegin, offsetInRealTOC);
|
|
assert(d);
|
|
mRealTOCOffset = offsetInRealTOC + mRealTOC->mGlobalPtr - mRealTOC->mBegin;
|
|
|
|
// grab ptr to beginning of stuff that's not code
|
|
mNextFreePostMethod = (Uint32*) ((Uint8*) inInfo.methodStart + inInfo.bodySize + inInfo.preMethodSize);
|
|
}
|
|
|
|
|
|
|
|
void PPCFormatter::
|
|
calculatePrePostMethod(Method& inMethod, Uint32& outPreMethodSize, Uint32& outPostMethodSize)
|
|
{
|
|
outPreMethodSize = 0;
|
|
outPostMethodSize = mEmitter.mCrossTOCPtrGlCount * kCrossTocPtrGlBytes;
|
|
|
|
#ifdef FIX_ME
|
|
PPCTraceInfo traceBack(inMethod.toString());
|
|
|
|
outPostMethodSize += traceBack.getFormattedSize(); //sTraceInfo.size(inMethod.toString());
|
|
#else
|
|
inMethod;
|
|
#endif
|
|
}
|
|
|
|
void PPCFormatter::
|
|
formatPostMethodToMemory(void* inWhere, const FormattedCodeInfo& inInfo)
|
|
{
|
|
#ifdef XP_MAC
|
|
#if 0
|
|
PPCTraceInfo traceBack(inInfo.method->toString());
|
|
|
|
traceBack.formatToMemory(inWhere, inInfo.bodySize);
|
|
#endif
|
|
inWhere;
|
|
inInfo;
|
|
#else
|
|
inWhere;
|
|
inInfo;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
Uint8* PPCFormatter::
|
|
createTransitionVector(const FormattedCodeInfo& inInfo)
|
|
{
|
|
TVector newTVector = {inInfo.methodStart, (void*) mRealTOC->mGlobalPtr};
|
|
Uint16 offset;
|
|
|
|
void* tvectorPtr = mRealTOC->addData(&newTVector, sizeof(newTVector), offset);
|
|
|
|
assert(tvectorPtr); // FIX-ME handle case where TOC blows up
|
|
|
|
return (Uint8*)tvectorPtr;
|
|
}
|
|
|
|
|
|
|