1175 lines
35 KiB
C++
1175 lines
35 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):
|
|
*/
|
|
|
|
#include "Fundamentals.h"
|
|
#include "prlog.h"
|
|
#include "prbit.h"
|
|
|
|
#include "HPPAEmitter.h"
|
|
#include "HPPAInstruction.h"
|
|
#include "HPPAMul.h"
|
|
#include "HPPAFuncs.h"
|
|
#include "ControlGraph.h"
|
|
#include "hppa.nad.burg.h"
|
|
#include "NativeCodeCache.h"
|
|
|
|
bool HPPAEmitter::initSpecialCallDone = false;
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------
|
|
*
|
|
* canUseDepi1 --
|
|
*
|
|
* Return true if a DEPI can be used instead of an OR. If mask contains
|
|
* only one sequence of consecutives ONES then a depi can be emitted.
|
|
* e.g.: 0...01...10...0 | 0...01...1 | 1...10...0
|
|
*
|
|
*-----------------------------------------------------------------------
|
|
*/
|
|
inline static bool
|
|
canUseDepi1(PRUint32 mask)
|
|
{
|
|
// If bits are consecutives mask & -mask will generate one bit at the first bit found.
|
|
// By adding it to the consecutive bits it will generate one bit after the last found.
|
|
mask += mask & -mask;
|
|
// Test that only one bit is set.
|
|
return (mask & (mask - 1)) == 0;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------
|
|
*
|
|
* canUseExtruOrDepi01 --
|
|
*
|
|
* Return true if a DEPI or an EXTRU can be used instead of an AND.
|
|
* If mask contains only one sequence of consecutives ZEROS then a depi
|
|
* or an extru can be emitted.
|
|
* e.g.: 1...10...01...1 | 0...01...1 | 1...10...0
|
|
*
|
|
*-----------------------------------------------------------------------
|
|
*/
|
|
inline static bool
|
|
canUseExtruOrDepi0(PRUint32 mask)
|
|
{
|
|
// Same as canUseDepi1, with ~mask.
|
|
return canUseDepi1(~mask);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitPrimitive(Primitive& inPrimitive, NamedRule inRule)
|
|
{
|
|
switch (inRule)
|
|
{
|
|
case emConst_I:
|
|
emitConst(inPrimitive, (*static_cast<const PrimConst *>(&inPrimitive)).value);
|
|
break;
|
|
case emArg_I:
|
|
case emArg_L:
|
|
case emArg_F:
|
|
case emArg_D:
|
|
case emArg_A:
|
|
PR_ASSERT(false);
|
|
break;
|
|
case emResult_M:
|
|
case emArg_M:
|
|
break;
|
|
case emResult_I:
|
|
emitResult(inPrimitive);
|
|
break;
|
|
case emIfLt:
|
|
emitCondBranch(inPrimitive, hcL);
|
|
break;
|
|
case emIfULt:
|
|
emitCondBranch(inPrimitive, hcLu);
|
|
break;
|
|
case emIfEq:
|
|
case emIfUEq:
|
|
emitCondBranch(inPrimitive, hcE);
|
|
break;
|
|
case emIfLe:
|
|
emitCondBranch(inPrimitive, hcLe);
|
|
break;
|
|
case emIfULe:
|
|
emitCondBranch(inPrimitive, hcLeu);
|
|
break;
|
|
case emIfGt:
|
|
emitCondBranch(inPrimitive, hcG);
|
|
break;
|
|
case emIfUGt:
|
|
emitCondBranch(inPrimitive, hcGu);
|
|
break;
|
|
case emIfLgt:
|
|
case emIfNe:
|
|
emitCondBranch(inPrimitive, hcNe);
|
|
break;
|
|
case emIfGe:
|
|
emitCondBranch(inPrimitive, hcGe);
|
|
break;
|
|
case emIfUGe:
|
|
emitCondBranch(inPrimitive, hcGeu);
|
|
break;
|
|
case emIfOrd:
|
|
case emIfUnord:
|
|
PR_ASSERT(false); // Shouldn't happen with int edges...
|
|
break;
|
|
case emOr_I:
|
|
emitInstruction(inPrimitive, OR);
|
|
break;
|
|
case emOrI_I:
|
|
emitOrImm (inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
case emAnd_I:
|
|
emitInstruction(inPrimitive, AND);
|
|
break;
|
|
case emAndI_I:
|
|
emitAndImm (inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
case emXor_I:
|
|
emitInstruction(inPrimitive, XOR);
|
|
break;
|
|
case emXorI_I:
|
|
emitXorImm (inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
case emShAdd_IIndirect:
|
|
emitShAddIndirect(inPrimitive);
|
|
break;
|
|
case emAdd_I:
|
|
case emAdd_A:
|
|
emitInstruction(inPrimitive, ADDL);
|
|
break;
|
|
case emAddI_I:
|
|
case emAddI_A:
|
|
emitAddImm(inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
|
|
UNIMP_CODE(BINARY_PRIMITIVE_SET(emMul, siSMul));
|
|
case emDivI_I:
|
|
emitDivImm(inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
case emMulI_I:
|
|
emitMulImm(inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
case emModE_I:
|
|
emitSpecialCall(inPrimitive, RemI);
|
|
break;
|
|
case emShlI_I:
|
|
emitShlImm(inPrimitive, inPrimitive.nthInputConstant(1));
|
|
break;
|
|
case emChkNull:
|
|
emitChkNull(inPrimitive);
|
|
break;
|
|
case emLimitR:
|
|
emitLimitR(inPrimitive);
|
|
break;
|
|
case emLimit:
|
|
emitLimit(inPrimitive);
|
|
break;
|
|
|
|
case emLdC_IRegisterIndirect:
|
|
emitLoad(inPrimitive, HPPA_REGISTER_INDIRECT | HPPA_LOAD_CONSTANT);
|
|
break;
|
|
case emLd_IRegisterIndirect:
|
|
emitLoad(inPrimitive, HPPA_REGISTER_INDIRECT);
|
|
break;
|
|
case emLdC_I:
|
|
emitLoad(inPrimitive, HPPA_LOAD_CONSTANT);
|
|
break;
|
|
case emLd_I:
|
|
emitLoad(inPrimitive);
|
|
break;
|
|
case emSt_I:
|
|
emitStore(inPrimitive);
|
|
break;
|
|
case emStI_I:
|
|
emitStoreImm(inPrimitive);
|
|
break;
|
|
case emStI_IRegisterIndirect:
|
|
emitStoreImm(inPrimitive, HPPA_REGISTER_INDIRECT);
|
|
break;
|
|
case emSt_IRegisterIndirect:
|
|
emitStore(inPrimitive, HPPA_REGISTER_INDIRECT);
|
|
break;
|
|
|
|
case emCallI_I:
|
|
case emCallI_L:
|
|
case emCallI_F:
|
|
case emCallI_D:
|
|
case emCallI_P:
|
|
UNIMP_CODE(emit_Call(inPrimitive));
|
|
break;
|
|
|
|
default:
|
|
//PR_ASSERT(false)
|
|
break;
|
|
}
|
|
}
|
|
|
|
Instruction& HPPAEmitter::
|
|
genInstruction(DataNode* inPrimitive, Pool& inPool, HPPAInstructionKind kind, HPPAInstructionFlags flags)
|
|
{
|
|
PR_ASSERT(HPPA_isValidInsn(kind));
|
|
|
|
switch(hiInfo[kind].format)
|
|
{
|
|
case 1:
|
|
PR_ASSERT(hasIM14(flags));
|
|
return *new(inPool) HPPAFormat1(inPrimitive, inPool, kind, flags);
|
|
|
|
case 6:
|
|
return *new(inPool) HPPAFormat6(inPrimitive, inPool, kind);
|
|
|
|
default:
|
|
PR_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitSpecialCall(Primitive& inPrimitive, HPPASpecialCallKind kind)
|
|
{
|
|
Instruction& call = *new(mPool) HPPASpecialCall(&inPrimitive, mPool, kind, HPPA_NULLIFICATION);
|
|
HPPASpecialCallInfo& callInfo = hscInfo[kind];
|
|
|
|
for (PRUint8 i = 0; i < callInfo.nUses; i++)
|
|
{
|
|
Instruction& copy = *new(mPool) HPPACopy(&inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(i), copy, 0);
|
|
VirtualRegister& vReg = defineTemporary(copy, 0);
|
|
vReg.preColorRegister(registerNumberToColor[arg0 - i]);
|
|
useTemporaryVR(call, vReg, i);
|
|
}
|
|
for (PRUint8 j = 0; j < callInfo.nDefines; j++)
|
|
{
|
|
Instruction& copy = *new(mPool) HPPACopy(&inPrimitive, mPool);
|
|
VirtualRegister& vReg = defineTemporary(call, j);
|
|
vReg.preColorRegister(registerNumberToColor[ret1 - j]);
|
|
useTemporaryVR(copy, vReg, 0);
|
|
defineProducer(nthOutputProducer(inPrimitive, j), copy, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitShAddIndirect(Primitive& inPrimitive)
|
|
{
|
|
// Need to get immediate argument from poShl_I producer's primitive
|
|
DataNode& immSource = inPrimitive.nthInput(1).getProducer().getNode();
|
|
DataNode& shiftedProducer = immSource.nthInputVariable(0);
|
|
DataNode& addedProducer = inPrimitive.nthInputVariable(0);
|
|
DataNode& resultProducer = inPrimitive;
|
|
PRUint8 shiftBy = immSource.nthInputConstant(1).i;
|
|
|
|
if (shiftBy == 0)
|
|
{
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
useProducer(addedProducer, addl, 0);
|
|
useProducer(shiftedProducer, addl, 1);
|
|
defineProducer(resultProducer, addl, 0);
|
|
}
|
|
else if (shiftBy <= 3)
|
|
{
|
|
Instruction& shiftAdd = genInstruction(&inPrimitive, mPool, shiftAddl[shiftBy]);
|
|
useProducer(shiftedProducer, shiftAdd, 0);
|
|
useProducer(addedProducer, shiftAdd, 1);
|
|
defineProducer(resultProducer, shiftAdd, 0);
|
|
}
|
|
else
|
|
{
|
|
Instruction& shift = *new(mPool) HPPAZdep(&inPrimitive, mPool, 31 - shiftBy, 32 - shiftBy);
|
|
useProducer(shiftedProducer, shift, 0);
|
|
defineProducer(immSource, shift, 0);
|
|
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
useProducer(addedProducer, addl, 0);
|
|
useProducer(immSource, addl, 1);
|
|
defineProducer(resultProducer, addl, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitStore(Primitive& inPrimitive, HPPAInstructionFlags flags)
|
|
{
|
|
if (flags & HPPA_REGISTER_INDIRECT)
|
|
{
|
|
// Need to get immediate argument from poAdd_A producer's primitive
|
|
DataNode& immSource = inPrimitive.nthInput(1).getProducer().getNode();
|
|
PRUint16 im14;
|
|
|
|
if (extractIM14(immSource.nthInputConstant(1), im14))
|
|
{
|
|
Instruction& store = *new(mPool) HPPAStore(&inPrimitive, mPool, STW, buildIM14(im14) | flags);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), store, 0);
|
|
useProducer(immSource.nthInputVariable(0), store, 1);
|
|
useProducer(inPrimitive.nthInputVariable(2), store, 2);
|
|
defineProducer(inPrimitive, store, 0);
|
|
}
|
|
else
|
|
{
|
|
emitAddImm(immSource, immSource.nthInputConstant(1));
|
|
emitStore(inPrimitive, flags & ~HPPA_REGISTER_INDIRECT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Instruction& store = *new(mPool) HPPAStore(&inPrimitive, mPool, STW, buildIM14(0) | flags);
|
|
store.standardUseDefine(*this);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitStoreToImm(Primitive& inPrimitive, HPPAInstructionFlags flags)
|
|
{
|
|
PR_ASSERT((flags & HPPA_REGISTER_INDIRECT) == 0);
|
|
Instruction& store = *new(mPool) HPPAStore(&inPrimitive, mPool, STW, buildIM14(0) | flags);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(1));
|
|
useProducer(inPrimitive.nthInputVariable(0), store, 0);
|
|
useTemporaryVR(store, constantVR, 1);
|
|
useProducer(inPrimitive.nthInputVariable(2), store, 2);
|
|
defineProducer(inPrimitive, store, 0);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitStoreImm(Primitive& inPrimitive, HPPAInstructionFlags flags)
|
|
{
|
|
if (flags & HPPA_REGISTER_INDIRECT)
|
|
{
|
|
// Need to get immediate argument from poAdd_A producer's primitive
|
|
DataNode& immSource = inPrimitive.nthInput(1).getProducer().getNode();
|
|
PRUint16 im14;
|
|
|
|
if (extractIM14(immSource.nthInputConstant(1), im14))
|
|
{
|
|
Instruction& store = *new(mPool) HPPAStore(&inPrimitive, mPool, STW, buildIM14(im14) | flags);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(2));
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), store, 0);
|
|
useProducer(immSource.nthInputVariable(0), store, 1);
|
|
useTemporaryVR(store, constantVR, 2);
|
|
defineProducer(inPrimitive, store, 0);
|
|
}
|
|
else
|
|
{
|
|
emitAddImm(immSource, immSource.nthInputConstant(1));
|
|
emitStoreImm(inPrimitive, flags & ~HPPA_REGISTER_INDIRECT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Instruction& store = *new(mPool) HPPAStore(&inPrimitive, mPool, STW, buildIM14(0) | flags);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(2));
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), store, 0);
|
|
useProducer(inPrimitive.nthInputVariable(1), store, 1);
|
|
useTemporaryVR(store, constantVR, 2);
|
|
defineProducer(inPrimitive, store, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitStoreImmToImm(Primitive& inPrimitive, HPPAInstructionFlags flags)
|
|
{
|
|
PR_ASSERT((flags & HPPA_REGISTER_INDIRECT) == 0);
|
|
Instruction& store = *new(mPool) HPPAStore(&inPrimitive, mPool, STW, buildIM14(0) | flags);
|
|
VirtualRegister& addressVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(1));
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(2));
|
|
useProducer(inPrimitive.nthInputVariable(0), store, 0);
|
|
useTemporaryVR(store, addressVR, 1);
|
|
useTemporaryVR(store, constantVR, 2);
|
|
defineProducer(inPrimitive, store, 0);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitLoad(Primitive& inPrimitive, HPPAInstructionFlags flags)
|
|
{
|
|
if (flags & HPPA_REGISTER_INDIRECT)
|
|
{
|
|
// Need to get immediate argument from poAdd_A producer's primitive
|
|
DataNode& immSource = inPrimitive.nthInput((flags & HPPA_LOAD_CONSTANT) ? 0 : 1).getProducer().getNode();
|
|
PRUint16 im14;
|
|
|
|
if (extractIM14(immSource.nthInputConstant(1), im14))
|
|
{
|
|
Instruction& load = *new(mPool) HPPALoad(&inPrimitive, mPool, LDW, buildIM14(im14) | flags);
|
|
|
|
useProducer(immSource.nthInputVariable(0), load, (flags & HPPA_LOAD_CONSTANT) ? 0 : 1);
|
|
if (!(flags & HPPA_LOAD_CONSTANT))
|
|
useProducer(inPrimitive.nthInputVariable(0), load, 0);
|
|
|
|
|
|
defineProducer(inPrimitive, load, 0);
|
|
if (flags & HPPA_LOAD_VOLATILE)
|
|
defineProducer(nthOutputProducer(inPrimitive, 1), load, 1);
|
|
}
|
|
else
|
|
{
|
|
emitAddImm(immSource, immSource.nthInputConstant(1));
|
|
emitLoad(inPrimitive, flags & ~HPPA_REGISTER_INDIRECT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Instruction& load = *new(mPool) HPPALoad(&inPrimitive, mPool, LDW, buildIM14(0) | flags);
|
|
load.standardUseDefine(*this);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitLoadFromImm(Primitive& inPrimitive, HPPAInstructionFlags flags)
|
|
{
|
|
PR_ASSERT((flags & HPPA_REGISTER_INDIRECT) == 0);
|
|
Instruction& load = *new(mPool) HPPALoad(&inPrimitive, mPool, LDW, buildIM14(0) | flags);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant((flags & HPPA_LOAD_CONSTANT) ? 0 : 1));
|
|
|
|
if (!(flags & HPPA_LOAD_CONSTANT))
|
|
useProducer(inPrimitive.nthInputVariable(0), load, 0);
|
|
useTemporaryVR(load, constantVR,(flags & HPPA_LOAD_CONSTANT) ? 0 : 1);
|
|
|
|
defineProducer(inPrimitive, load, 0);
|
|
if (flags & HPPA_LOAD_VOLATILE)
|
|
defineProducer(nthOutputProducer(inPrimitive, 1), load, 1);
|
|
}
|
|
|
|
VirtualRegister& HPPAEmitter::
|
|
genLoadConstant(DataNode& inPrimitive, const Value& value, bool checkIM14)
|
|
{
|
|
// It is possible to use the instruction zdepi to generate a constant.
|
|
// also zvdepi might be used if the constant is shifted after.
|
|
|
|
PRUint16 im14;
|
|
if (checkIM14 && extractIM14(value, im14))
|
|
{
|
|
Instruction& ldi = *new(mPool) HPPALdi(&inPrimitive, mPool, buildIM14(im14));
|
|
return defineTemporary(ldi, 0);
|
|
}
|
|
else
|
|
{
|
|
Instruction& ldil = *new(mPool) HPPALdil(&inPrimitive, mPool, buildIM21(HPPA_LEFT(value.i)));
|
|
VirtualRegister& constantVR = defineTemporary(ldil, 0);
|
|
|
|
if (HPPA_RIGHT(value.i) != 0)
|
|
{
|
|
Instruction& ldo = *new(mPool) HPPALdo(&inPrimitive, mPool, buildIM14(HPPA_RIGHT(value.i)));
|
|
useTemporaryVR(ldo, constantVR, 0);
|
|
redefineTemporary(ldo, constantVR, 0);
|
|
}
|
|
return constantVR;
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitLimitR(Primitive& inPrimitive)
|
|
{
|
|
ControlNode& endNode = inPrimitive.getContainer()->controlGraph.getEndNode();
|
|
PRUint8 constant;
|
|
|
|
if (extractIM5(inPrimitive.nthInputConstant(0), constant))
|
|
{
|
|
Instruction& compare = *new(mPool) HPPACondBranch(&inPrimitive, mPool, endNode, COMIBF, hcLe, buildIM5(constant) | HPPA_NULLIFICATION);
|
|
useProducer(inPrimitive.nthInputVariable(1), compare, 0);
|
|
inPrimitive.setInstructionRoot(&compare);
|
|
}
|
|
else
|
|
{
|
|
Instruction& compare = *new(mPool) HPPACondBranch(&inPrimitive, mPool, endNode, COMBF, hcLe, HPPA_NULLIFICATION);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(0));
|
|
|
|
useProducer(inPrimitive.nthInputVariable(1), compare, 0);
|
|
useTemporaryVR(compare, constantVR, 1);
|
|
inPrimitive.setInstructionRoot(&compare);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitLimit(Primitive& inPrimitive)
|
|
{
|
|
ControlNode& endNode = inPrimitive.getContainer()->controlGraph.getEndNode();
|
|
Instruction& compare = *new(mPool) HPPACondBranch(&inPrimitive, mPool, endNode, COMBF, hcL, HPPA_NULLIFICATION);
|
|
compare.standardUseDefine(*this);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitChkNull(Primitive& inPrimitive)
|
|
{
|
|
ControlNode& endNode = inPrimitive.getContainer()->controlGraph.getEndNode();
|
|
Instruction& compare = *new(mPool) HPPACondBranch(&inPrimitive, mPool, endNode, COMIBT, hcE, buildIM5(0) | HPPA_NULLIFICATION);
|
|
compare.standardUseDefine(*this);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitResult(Primitive& inPrimitive)
|
|
{
|
|
VirtualRegister* returnVr;
|
|
if (inPrimitive.nthInputIsConstant(0))
|
|
{
|
|
returnVr = &genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(0));
|
|
}
|
|
else
|
|
{
|
|
Instruction& copy = *new(mPool) HPPACopy(&inPrimitive, mPool);
|
|
returnVr = &defineTemporary(copy, 0);
|
|
useProducer(inPrimitive.nthInputVariable(0), copy, 0);
|
|
}
|
|
|
|
returnVr->preColorRegister(registerNumberToColor[ret0]);
|
|
|
|
InsnExternalUse& externalUse = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
|
|
useTemporaryVR(externalUse, *returnVr, 0);
|
|
inPrimitive.setInstructionRoot(&externalUse);
|
|
}
|
|
|
|
VirtualRegister& HPPAEmitter::
|
|
genShiftAdd(Primitive& inPrimitive, const PRUint8 shiftBy, VirtualRegister& shiftedReg, VirtualRegister& addedReg)
|
|
{
|
|
// will emit (shiftedReg << shiftBy) + addedReg
|
|
if (shiftBy == 0)
|
|
{
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
useTemporaryVR(addl, shiftedReg, 0);
|
|
useTemporaryVR(addl, addedReg, 1);
|
|
return defineTemporary(addl, 0);
|
|
}
|
|
else if (shiftBy <= 3)
|
|
{
|
|
Instruction& shiftAdd = genInstruction(&inPrimitive, mPool, shiftAddl[shiftBy]);
|
|
useTemporaryVR(shiftAdd, shiftedReg, 0);
|
|
useTemporaryVR(shiftAdd, addedReg, 1);
|
|
return defineTemporary(shiftAdd, 0);
|
|
}
|
|
else
|
|
{
|
|
Instruction& shift = *new(mPool) HPPAZdep(&inPrimitive, mPool, 31 - shiftBy, 32 - shiftBy);
|
|
useTemporaryVR(shift, shiftedReg, 0);
|
|
VirtualRegister& vReg = defineTemporary(shift, 0);
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
useTemporaryVR(addl, vReg, 0);
|
|
useTemporaryVR(addl, addedReg, 1);
|
|
return defineTemporary(addl, 0);
|
|
}
|
|
}
|
|
|
|
VirtualRegister& HPPAEmitter::
|
|
genShiftSub(Primitive& inPrimitive, const PRUint8 shiftBy, VirtualRegister& shiftedReg, VirtualRegister& subtractedReg, bool neg)
|
|
{
|
|
// will emit (shiftedReg << shiftBy) - subtractedReg OR subtractedReg - (shiftedReg << shiftBy) if neg is true.
|
|
PRUint8 shiftedPos = neg ? 1 : 0;
|
|
PRUint8 subPos = neg ? 0 : 1;
|
|
|
|
if (shiftBy == 0)
|
|
{
|
|
Instruction& sub = *new(mPool) HPPASub(&inPrimitive, mPool);
|
|
useTemporaryVR(sub, shiftedReg, shiftedPos);
|
|
useTemporaryVR(sub, subtractedReg, subPos);
|
|
return defineTemporary(sub, 0);
|
|
}
|
|
else
|
|
{
|
|
Instruction& shift = *new(mPool) HPPAZdep(&inPrimitive, mPool, 31 - shiftBy, 32 - shiftBy);
|
|
useTemporaryVR(shift, shiftedReg, 0);
|
|
VirtualRegister& vReg = defineTemporary(shift, 0);
|
|
Instruction& sub = *new(mPool) HPPASub(&inPrimitive, mPool);
|
|
useTemporaryVR(sub, vReg, shiftedPos);
|
|
useTemporaryVR(sub, subtractedReg, subPos);
|
|
return defineTemporary(sub, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitMulImm(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
enum MethodType
|
|
{
|
|
mRegular,
|
|
mOpposite,
|
|
mAddMultiplicand
|
|
};
|
|
|
|
MulAlgorithm algorithm, tempAlgorithm;
|
|
VirtualRegister* accum;
|
|
VirtualRegister* multiplicand;
|
|
MethodType methodType = mRegular;
|
|
PRUint8 mulCost = 30; // is it true for all the pa proc ?
|
|
DEBUG_ONLY(PRInt32 val;)
|
|
|
|
// Try the multiplication by value.i
|
|
getMulAlgorithm(&algorithm, value.i, mulCost);
|
|
|
|
// Try the multiplication by -value.i
|
|
getMulAlgorithm(&tempAlgorithm, -value.i, mulCost - 4);
|
|
if ((tempAlgorithm.cost + 4) < algorithm.cost)
|
|
{
|
|
algorithm = tempAlgorithm;
|
|
algorithm.cost += 4; // cost for neg.
|
|
methodType = mOpposite;
|
|
}
|
|
|
|
// Try the multiplication by value.i-1
|
|
getMulAlgorithm(&tempAlgorithm, value.i - 1, mulCost);
|
|
if ((tempAlgorithm.cost + 4) < algorithm.cost)
|
|
{
|
|
algorithm = tempAlgorithm;
|
|
algorithm.cost += 4; // cost for ldo.
|
|
methodType = mAddMultiplicand;
|
|
}
|
|
|
|
if (algorithm.cost < mulCost)
|
|
{
|
|
// found a cheaper way to do the multiply.
|
|
if (algorithm.operations[0] == maZero)
|
|
{
|
|
Instruction& ldi = *new(mPool) HPPALdi(&inPrimitive, mPool, buildIM14(0));
|
|
defineProducer(inPrimitive, ldi, 0);
|
|
return;
|
|
}
|
|
else if (algorithm.operations[0] == maMultiplicand)
|
|
{
|
|
Instruction& copy = *new(mPool) HPPACopy(&inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), copy, 0);
|
|
accum = &defineTemporary(copy, 0);
|
|
DEBUG_ONLY(val = 1;)
|
|
}
|
|
else
|
|
{
|
|
PR_ASSERT(false); // there is an error in getMulAlgorithm.
|
|
}
|
|
|
|
multiplicand = inPrimitive.nthInputVariable(0).getVirtualRegisterAnnotation();
|
|
for (PRUint8 n = 1; n < algorithm.nOperations; n++)
|
|
{
|
|
PRUint8 shiftBy = algorithm.shiftAmount[n];
|
|
|
|
switch (algorithm.operations[n])
|
|
{
|
|
case maShiftValue: // accum = accum << shiftBy
|
|
{
|
|
Instruction& zdep = *new(mPool) HPPAZdep(&inPrimitive, mPool, 31 - shiftBy, 32 - shiftBy);
|
|
useTemporaryVR(zdep, *accum, 0);
|
|
accum = &defineTemporary(zdep, 0);
|
|
DEBUG_ONLY(val <<= shiftBy);
|
|
}
|
|
break;
|
|
|
|
case maAddValueToShiftMultiplicand: // accum = accum + (multiplicand << shiftBy)
|
|
accum = &genShiftAdd(inPrimitive, shiftBy, *multiplicand, *accum);
|
|
DEBUG_ONLY(val += (1 << shiftBy);)
|
|
break;
|
|
|
|
case maSubShiftMultiplicandFromValue: // accum = accum - (multiplicand << shiftBy)
|
|
accum = &genShiftSub(inPrimitive, shiftBy, *multiplicand, *accum, true);
|
|
DEBUG_ONLY(val -= (1 << shiftBy);)
|
|
break;
|
|
|
|
case maAddValueToShiftValue: // accum = (accum << shiftBy) + accum
|
|
accum = &genShiftAdd(inPrimitive, shiftBy, *accum, *accum);
|
|
DEBUG_ONLY(val += (val << shiftBy);)
|
|
break;
|
|
|
|
case maSubValueFromShiftValue: // accum = (accum << shiftBy) - accum
|
|
accum = &genShiftSub(inPrimitive, shiftBy, *accum, *accum, false);
|
|
DEBUG_ONLY(val = (val << shiftBy) - val;)
|
|
break;
|
|
|
|
case maAddMultiplicandToShiftValue: // accum = (accum << shiftBy) + multiplicand
|
|
accum = &genShiftAdd(inPrimitive, shiftBy, *accum, *multiplicand);
|
|
DEBUG_ONLY(val = (val << shiftBy) + 1;)
|
|
break;
|
|
|
|
case maSubMultiplicandFromShiftValue: // accum = (accum << shiftBy) - multiplicand
|
|
accum = &genShiftSub(inPrimitive, shiftBy, *accum, *multiplicand, false);
|
|
DEBUG_ONLY(val = (val << shiftBy) - 1;)
|
|
break;
|
|
|
|
default:
|
|
PR_ASSERT(false); // there is an error in getMulAlgorithm
|
|
}
|
|
}
|
|
|
|
switch (methodType)
|
|
{
|
|
case mRegular:
|
|
defineProducerWithExistingVirtualRegister(*accum, inPrimitive,
|
|
*accum->getDefiningInstruction(), 0);
|
|
break;
|
|
case mOpposite:
|
|
{
|
|
Instruction& neg = *new(mPool) HPPASub(&inPrimitive, mPool, HPPA_R1_IS_ZERO);
|
|
useTemporaryVR(neg, *accum, 0);
|
|
defineProducer(inPrimitive, neg, 0);
|
|
DEBUG_ONLY(val = -val;)
|
|
}
|
|
break;
|
|
case mAddMultiplicand:
|
|
{
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
useTemporaryVR(addl, *accum, 0);
|
|
useTemporaryVR(addl, *multiplicand, 1);
|
|
defineProducer(inPrimitive, addl, 0);
|
|
DEBUG_ONLY(val = val + 1;)
|
|
}
|
|
break;
|
|
}
|
|
DEBUG_ONLY(PR_ASSERT(val = value.i);)
|
|
}
|
|
else
|
|
{
|
|
Instruction& xmpyu = *new(mPool) HPPAXmpyu(&inPrimitive, mPool);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, value);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), xmpyu, 0, vrcFixedPoint);
|
|
useTemporaryVR(xmpyu, constantVR, 1, vrcFixedPoint);
|
|
defineProducer(inPrimitive, xmpyu, 0, vrcFixedPoint);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitDivImm(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
PRUint32 shift = value.i;
|
|
if(shift != 0 && (shift & (shift - 1)) == 0)
|
|
{
|
|
PRUint8 shiftBy;
|
|
PR_FLOOR_LOG2(shiftBy, shift);
|
|
|
|
Instruction& extru = *new(mPool) HPPAExtru(&inPrimitive, mPool, 0, 1);
|
|
useProducer(inPrimitive.nthInputVariable(0), extru, 0);
|
|
VirtualRegister& tempVR = defineTemporary(extru, 0);
|
|
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), addl, 0);
|
|
useTemporaryVR(addl, tempVR, 1);
|
|
redefineTemporary(addl, tempVR, 0);
|
|
|
|
Instruction& extrs = *new(mPool) HPPAExtrs(&inPrimitive, mPool, 31 - shiftBy, 32 - shiftBy);
|
|
useTemporaryVR(extrs, tempVR, 0);
|
|
defineProducer(inPrimitive, extrs, 0);
|
|
}
|
|
else
|
|
{
|
|
PR_ASSERT(false); // FIXME
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitAddImm(DataNode& inPrimitive, const Value& value)
|
|
{
|
|
PRUint16 im14;
|
|
if(extractIM14(value, im14))
|
|
{
|
|
Instruction& add = *new(mPool) HPPALdo(&inPrimitive, mPool, buildIM14(im14));
|
|
add.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
Instruction& addl = *new(mPool) HPPAAddl(&inPrimitive, mPool);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, value);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), addl, 0);
|
|
useTemporaryVR(addl, constantVR, 1);
|
|
defineProducer(inPrimitive, addl, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitConst(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
PRUint16 im14;
|
|
if (extractIM14(value, im14))
|
|
{
|
|
Instruction& ldi = *new(mPool) HPPALdi(&inPrimitive, mPool, buildIM14(im14));
|
|
ldi.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
Instruction& ldil = *new(mPool) HPPALdil(&inPrimitive, mPool, buildIM21(HPPA_LEFT(value.i)));
|
|
VirtualRegister& vReg = *defineProducer(inPrimitive, ldil, 0);
|
|
|
|
if (HPPA_RIGHT(value.i) != 0)
|
|
{
|
|
Instruction& ldo = *new(mPool) HPPALdo(&inPrimitive, mPool, buildIM14(HPPA_RIGHT(value.i)));
|
|
useTemporaryVR(ldo, vReg, 0);
|
|
redefineTemporary(ldo, vReg, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitShlImm(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
Instruction& zdep = *new(mPool) HPPAZdep(&inPrimitive, mPool, 31 - value.i, 32 - value.i);
|
|
zdep.standardUseDefine(*this);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitAndImm(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
if (canUseExtruOrDepi0(value.i))
|
|
{
|
|
PRUint32 mask = value.i;
|
|
PRUint8 ls0, ls1, ms0, p, len;
|
|
|
|
// count the number of low ONES
|
|
for (ls0 = 0; ls0 < 32; ls0++)
|
|
if ((mask & (1 << ls0)) == 0)
|
|
break;
|
|
|
|
// count the number of middle ZEROS
|
|
for (ls1 = ls0; ls1 < 32; ls1++)
|
|
if ((mask & (1 << ls1)) != 0)
|
|
break;
|
|
|
|
// count then number of high ONES
|
|
for (ms0 = ls1; ms0 < 32; ms0++)
|
|
if ((mask & (1 << ms0)) == 0)
|
|
break;
|
|
|
|
// Be sure that we counted all the bits
|
|
PR_ASSERT(ms0 == 32);
|
|
|
|
if (ls1 == 32)
|
|
{
|
|
// The sequence is 0...01...1
|
|
len = ls0;
|
|
PR_ASSERT(len);
|
|
|
|
Instruction& extru = *new(mPool) HPPAExtru(&inPrimitive, mPool, 31, len);
|
|
extru.standardUseDefine(*this);
|
|
}
|
|
else
|
|
{
|
|
// The sequence is 1...10...01...1 | 1...10...0
|
|
p = 31 - ls0;
|
|
len = ls1 - ls0;
|
|
|
|
Instruction& copy = *new(mPool) HPPACopy(&inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), copy, 0);
|
|
VirtualRegister& vReg = *defineProducer(inPrimitive, copy, 0);
|
|
|
|
Instruction& depi = *new(mPool) HPPADepi(&inPrimitive, mPool, 31 - p, 32 - len, buildIM5(0));
|
|
useTemporaryVR(depi, vReg, 0);
|
|
redefineTemporary(depi, vReg, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No optimization is possible. Emit the regular AND with a load constant before.
|
|
Instruction& andInsn = *new(mPool) HPPAAnd(&inPrimitive, mPool);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, value);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), andInsn, 0);
|
|
useTemporaryVR(andInsn, constantVR, 1);
|
|
defineProducer(inPrimitive, andInsn, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitXorImm(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
Instruction& xorInsn = *new(mPool) HPPAXor(&inPrimitive, mPool);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, value);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), xorInsn, 0);
|
|
useTemporaryVR(xorInsn, constantVR, 1);
|
|
defineProducer(inPrimitive, xorInsn, 0);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitOrImm(Primitive& inPrimitive, const Value& value)
|
|
{
|
|
if (canUseDepi1(value.i))
|
|
{
|
|
// We can emit a depi instruction.
|
|
PRUint32 mask = value.i;
|
|
PRUint8 bs0, bs1, p, len;
|
|
|
|
// Count the number of low ZEROS.
|
|
for (bs0 = 0; bs0 < 32; bs0++)
|
|
if ((mask & (1 << bs0)) != 0)
|
|
break;
|
|
|
|
// Count the number of middle ONES
|
|
for (bs1 = bs0; bs1 < 32; bs1++)
|
|
if ((mask & (1 << bs1)) == 0)
|
|
break;
|
|
|
|
// Be sure that we counted all bits in the sequence. x...x1...10...0 | x...x1...1
|
|
// where x...x must be 0...0
|
|
PR_ASSERT(((bs1 == 32) || (((PRUint32) 1 << bs1) > mask)));
|
|
|
|
p = 31 - bs0;
|
|
len = bs1 - bs0;
|
|
|
|
Instruction& copy = *new(mPool) HPPACopy(&inPrimitive, mPool);
|
|
useProducer(inPrimitive.nthInputVariable(0), copy, 0);
|
|
VirtualRegister& vReg = *defineProducer(inPrimitive, copy, 0);
|
|
|
|
Instruction& depi = *new(mPool) HPPADepi(&inPrimitive, mPool, 31 - p, 32 - len, buildIM5(-1));
|
|
useTemporaryVR(depi, vReg, 0);
|
|
redefineTemporary(depi, vReg, 0);
|
|
}
|
|
else
|
|
{
|
|
// No optimization is possible. Emit the regular OR with a load constant before.
|
|
Instruction& orInsn = *new(mPool) HPPAOr(&inPrimitive, mPool);
|
|
VirtualRegister& constantVR = genLoadConstant(inPrimitive, value);
|
|
|
|
useProducer(inPrimitive.nthInputVariable(0), orInsn, 0);
|
|
useTemporaryVR(orInsn, constantVR, 1);
|
|
defineProducer(inPrimitive, orInsn, 0);
|
|
}
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitInstruction(Primitive& inPrimitive, HPPAInstructionKind kind)
|
|
{
|
|
Instruction& newInsn = genInstruction(&inPrimitive, mPool, kind);
|
|
newInsn.standardUseDefine(*this);
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitArguments(ControlBegin& inBeginNode)
|
|
{
|
|
PRUint32 curParamWords; // number of words of argument space used
|
|
PRUint32 curFloatingPointArg; // number of floating point arguments
|
|
|
|
InsnExternalDefine& defineInsn = *new(mPool) InsnExternalDefine(&inBeginNode.arguments[0], mPool, inBeginNode.nArguments * 2);
|
|
|
|
PRUint32 curArgIdx; // current index into the arguments in the ControlBegin
|
|
|
|
curParamWords = 0;
|
|
curFloatingPointArg = 0;
|
|
for (curArgIdx = 0; curArgIdx < inBeginNode.nArguments && curParamWords < 4; curArgIdx++)
|
|
{
|
|
PrimArg& curArg = inBeginNode.arguments[curArgIdx];
|
|
|
|
switch (curArg.getOperation())
|
|
{
|
|
case poArg_I:
|
|
case poArg_A:
|
|
{
|
|
Instruction& copyInsn = *new(mPool) HPPACopy(&curArg, mPool);
|
|
|
|
// hook up this vr to the external define FIX-ME
|
|
VirtualRegister& inputVr = defineTemporary(defineInsn, curArgIdx);
|
|
inputVr.preColorRegister(registerNumberToColor[arg0-curParamWords]);
|
|
|
|
// emit the copy
|
|
useTemporaryVR(copyInsn, inputVr, 0);
|
|
defineProducer(curArg, copyInsn, 0);
|
|
|
|
curParamWords++;
|
|
break;
|
|
}
|
|
case poArg_L:
|
|
PR_ASSERT(false); // FIXME
|
|
|
|
case poArg_F:
|
|
PR_ASSERT(false); // FIXME
|
|
|
|
case poArg_D:
|
|
PR_ASSERT(false); // FIXME
|
|
|
|
break;
|
|
|
|
case poArg_M:
|
|
break;
|
|
|
|
default:
|
|
PR_ASSERT(false); // Should not happen
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
// check for half stack half reg case
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
emitCondBranch(Primitive& inPrimitive, HPPAConditionKind kind)
|
|
{
|
|
ControlNode& target = ControlIf::cast(*inPrimitive.getContainer())->getTrueIfEdge().target;
|
|
DataNode& compare = inPrimitive.nthInput(0).getProducer().getNode(); // get the compare.
|
|
PRUint8 constant;
|
|
bool negate = hcInfo[kind].f;
|
|
|
|
switch (compare.getOperation())
|
|
{
|
|
case poCmpU_I:
|
|
case poCmpU_A:
|
|
case poCmp_I:
|
|
{
|
|
Instruction& cb = *new(mPool) HPPACondBranch(&inPrimitive, mPool, target, negate ? COMBF : COMBT,
|
|
negate ? HPPAConditionKind(kind & 7) : kind, HPPA_NULLIFICATION);
|
|
useProducer(compare.nthInputVariable(0), cb, 0);
|
|
useProducer(compare.nthInputVariable(1), cb, 1);
|
|
inPrimitive.setInstructionRoot(&cb);
|
|
}
|
|
break;
|
|
|
|
case poCmpUI_I:
|
|
case poCmpUI_A:
|
|
case poCmpI_I:
|
|
if (extractIM5(compare.nthInputConstant(1), constant))
|
|
{
|
|
kind = hcInfo[kind].swapped;
|
|
negate = hcInfo[kind].f;
|
|
Instruction& cb = *new(mPool) HPPACondBranch(&inPrimitive, mPool, target, negate ? COMIBF : COMIBT,
|
|
negate ? HPPAConditionKind(kind & 7) : kind, buildIM5(constant)
|
|
| HPPA_NULLIFICATION);
|
|
useProducer(compare.nthInputVariable(0), cb, 0);
|
|
inPrimitive.setInstructionRoot(&cb);
|
|
}
|
|
else
|
|
{
|
|
Instruction& cb = *new(mPool) HPPACondBranch(&inPrimitive, mPool, target, negate ? COMBF : COMBT,
|
|
negate ? HPPAConditionKind(kind & 7) : kind, HPPA_NULLIFICATION);
|
|
VirtualRegister& constantVR = genLoadConstant(compare, compare.nthInputConstant(1));
|
|
useProducer(compare.nthInputVariable(0), cb, 0);
|
|
useTemporaryVR(cb, constantVR, 1);
|
|
inPrimitive.setInstructionRoot(&cb);
|
|
}
|
|
break;
|
|
|
|
case poCmp_L:
|
|
case poCmpU_L:
|
|
case poFCmp_F:
|
|
case poFCmp_D:
|
|
case poConst_C:
|
|
default:
|
|
PR_ASSERT(false); // FIXME
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool HPPAEmitter::
|
|
emitCopyAfter(DataNode& inDataNode, SortedDoublyLinkedList<Instruction>::iterator where, VirtualRegister& fromVr, VirtualRegister& toVr)
|
|
{
|
|
#define COPY_KIND(fc, tc) ((((fc) & 0xff) << 8) | ((tc) & 0xff))
|
|
|
|
PRUint32 copyKind = COPY_KIND(fromVr.getClass(),toVr.getClass());
|
|
|
|
switch(copyKind)
|
|
{
|
|
case COPY_KIND(vrcInteger, vrcInteger):
|
|
{
|
|
Instruction& copy = *new(mPool) HPPACopy(&inDataNode, mPool);
|
|
copy.addUse(0, fromVr);
|
|
copy.addDefine(0, toVr);
|
|
toVr.setDefiningInstruction(copy);
|
|
|
|
where->append(copy);
|
|
}
|
|
return false;
|
|
|
|
case COPY_KIND(vrcInteger, vrcFixedPoint):
|
|
{
|
|
Instruction& intStore = *new(mPool) HPPAStoreIntegerToConvertStackSlot(&inDataNode, mPool, fromVr);
|
|
Instruction& fixedLoad = *new(mPool) HPPALoadFixedPointFromConvertStackSlot(&inDataNode, mPool, toVr);
|
|
toVr.setDefiningInstruction(fixedLoad);
|
|
// FIXME use & def
|
|
|
|
where->append(intStore);
|
|
intStore.append(fixedLoad);
|
|
}
|
|
return true;
|
|
|
|
case COPY_KIND(vrcFixedPoint, vrcInteger):
|
|
{
|
|
Instruction& fixedStore = *new(mPool) HPPAStoreFixedPointToConvertStackSlot(&inDataNode, mPool, fromVr);
|
|
Instruction& intLoad = *new(mPool) HPPALoadIntegerFromConvertStackSlot(&inDataNode, mPool, toVr);
|
|
toVr.setDefiningInstruction(intLoad);
|
|
// FIXME use & def
|
|
|
|
where->append(fixedStore);
|
|
fixedStore.append(intLoad);
|
|
}
|
|
return true;
|
|
|
|
default:
|
|
fprintf(stdout, "unhandled copy %d->%d\n", fromVr.getClass(), toVr.getClass());
|
|
return false;
|
|
}
|
|
#undef COPY_KIND
|
|
}
|
|
|
|
Instruction& HPPAEmitter::
|
|
emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget)
|
|
{
|
|
Instruction& branch = *new(mPool) HPPAAbsoluteBranch(&inDataNode, mPool, inTarget, BL, HPPA_NULLIFICATION);
|
|
return branch;
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
initSpecialCall()
|
|
{
|
|
#if defined(hppa)
|
|
PRUint32* codeSpaceBase = HPPASpecialCodeBegin;
|
|
PRUint32* codeSpaceLimit = HPPASpecialCodeEnd;
|
|
PRUint32 specialCodeSize = (codeSpaceLimit - codeSpaceBase) * sizeof(PRUint32);
|
|
|
|
PRUint32* specialCode = (PRUint32 *) NativeCodeCache::getCache().acquireMemory(specialCodeSize + 4);
|
|
specialCode = (PRUint32 *) (((PRUint32) specialCode) + 3 & -4); // round up
|
|
|
|
copy(codeSpaceBase, codeSpaceLimit, specialCode);
|
|
|
|
for (PRUint8 i = 0; i < nSpecialCalls; i++)
|
|
{
|
|
PRUint32 offset = ((PRUint32 *) hscInfo[i].address) - codeSpaceBase;
|
|
MethodDescriptor md(hscInfo[i].string);
|
|
|
|
NativeCodeCache::getCache().mapMemoryToMethod(md, (void *) &specialCode[offset]);
|
|
#ifdef DEBUG
|
|
hscInfo[i].address = (void *) &specialCode[offset];
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
#endif /* defined(hppa) */
|
|
}
|
|
|
|
void HPPAEmitter::
|
|
formatPrologToMemory(void* inWhere)
|
|
{
|
|
PRUint32* prolog = (PRUint32 *) inWhere;
|
|
|
|
// 00: where + 00000008
|
|
// 04: 00000000
|
|
// 08: bl <+0x10>, %rp 0xe8400020
|
|
// 0c: nop 0x08000240
|
|
// 10: ldw -18(%sr0,%sp),%rp 0x4bc23fd1
|
|
// 14: ldsid (%sr0,%rp),%r1 0x004010a1
|
|
// 18: mtsp %r1,%sr0 0x00011820
|
|
// 1c: be,n 0(%sr0,%rp) 0xe0400002
|
|
// 20: ..... func ....
|
|
|
|
prolog[0] = ((PRUint32) prolog) + 8;
|
|
prolog[1] = 0x00000000;
|
|
prolog[2] = 0xe8400020;
|
|
prolog[3] = 0x08000240;
|
|
prolog[4] = 0x4bc23fd1;
|
|
prolog[5] = 0x004010a1;
|
|
prolog[6] = 0x00011820;
|
|
prolog[7] = 0xe0400002;
|
|
}
|