dmose%mozilla.org 2ccab49e6d updating license boilerplate to xPL v1.1
git-svn-id: svn://10.0.0.236/trunk@52526 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-02 06:38:29 +00:00

318 lines
11 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):
*/
// PPCCalls.h
//
// Scott M. Silver
//
#ifndef _H_PPCCALLS
#define _H_PPCCALLS
#include "PPC601AppleMacOSEmitter.h"
#include "AssembledInstructions.h"
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic>
class Call :
public PPCInstructionXY
{
public:
static inline bool hasReturnValue(DataNode& inDataNode); // determines whether Call Primitive has return value
static inline uint8 numberOfArguments(DataNode& inDataNode); // determines number of real arguments (not including store)
Call(DataNode* inDataNode, Pool& inPool, uint8 inRegisterArguments, bool inHasReturnValue, PPCEmitter& inEmitter, void* inFunc = NULL);
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter);
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return (8); }
virtual InstructionFlags getFlags() const { return (ifCall); }
protected:
int16 mTOCOffset; // offset in accumulator TOC
TVector* mCalleeAddress; // addres of cuntion
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, "call %X", mCalleeAddress); }
#endif
};
template<bool tHasIncomingStore, bool tHasOutgoingStore>
class CallS :
public Call<tHasIncomingStore, tHasOutgoingStore, false, false>
{
public:
inline CallS(DataNode* inDataNode, Pool& inPool, uint8 inRegisterArguments, bool inHasReturnValue, PPCEmitter& inEmitter, void* inFunc) :
Call<tHasIncomingStore, tHasOutgoingStore, false, false>(inDataNode, inPool, inRegisterArguments, inHasReturnValue, inEmitter, inFunc) { }
};
#ifdef MANUAL_TEMPLATES
template class Call<true, true, false, false>;
template class Call<true, false, false, false>;
template class Call<false, false, false, false>;
template class Call<true, true, true, false>;
template class Call<true, true, true, true>;
#endif
typedef CallS<true, true> CallS_V;
typedef CallS<true, false> CallS_;
typedef CallS<false, false> CallS_C;
typedef Call<true, true, true, false> Call_;
// Dynamically dispatched call
class CallD_ :
public Call<true, true, true, true>
{
public:
inline CallD_(DataNode* inDataNode, Pool& inPool, uint8 inRegisterArguments, bool inHasReturnValue, PPCEmitter& inEmitter) :
Call<true, true, true, true>(inDataNode, inPool, inRegisterArguments, inHasReturnValue, inEmitter) { }
void formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& inFormatter);
};
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic> bool
Call<tHasIncomingStore, tHasOutgoingStore, tHasFunctionAddress, tIsDynamic>::
hasReturnValue(DataNode& inDataNode)
{
bool hasReturnValue = (inDataNode.getOutgoingEdgesBegin() + tHasOutgoingStore < inDataNode.getOutgoingEdgesEnd());
return (hasReturnValue);
}
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic> uint8
Call<tHasIncomingStore, tHasOutgoingStore,tHasFunctionAddress, tIsDynamic>::
numberOfArguments(DataNode& inDataNode)
{
DataConsumer* firstArg;
DataConsumer* lastArg;
assert(!(tHasFunctionAddress && !tHasIncomingStore)); // no such primitive
firstArg = inDataNode.getInputsBegin() + tHasFunctionAddress + tHasIncomingStore;
lastArg = inDataNode.getInputsEnd();
return (lastArg - firstArg);
}
// -> mem regarg1 regarg2 regarg3 regarg3
// <- mem [returnval]
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic>
Call<tHasIncomingStore, tHasOutgoingStore, tHasFunctionAddress, tIsDynamic>::
Call(DataNode* inDataNode, Pool& inPool, uint8 inRegisterArguments, bool /*inHasReturnValue*/, PPCEmitter& inEmitter, void* inFunc) :
PPCInstructionXY(inDataNode, inPool, inRegisterArguments + tHasIncomingStore + tIsDynamic, 1 + tHasOutgoingStore)
{
if (!tIsDynamic)
inEmitter.mCrossTOCPtrGlCount++;
const DoublyLinkedList<DataConsumer>& projectionConsumers = inDataNode->getConsumers();
DoublyLinkedList<DataConsumer>::iterator curProjectionEdge = projectionConsumers.begin();
DataNode* returnValProducer;
// outgoing store
if (tHasOutgoingStore)
{
DataNode& projectionA = projectionConsumers.get(curProjectionEdge).getNode();
DataNode* projectionB = (projectionConsumers.done(curProjectionEdge = projectionConsumers.advance(curProjectionEdge))) ? 0 : &projectionConsumers.get(curProjectionEdge).getNode();
if (projectionA.hasKind(vkMemory))
{
inEmitter.defineProducer(projectionA, *this, 0); // -> mem
returnValProducer = projectionB;
}
else
{
assert(projectionB); // projectionB must be the memory producer
inEmitter.defineProducer(*projectionB, *this, 0); // -> mem
returnValProducer = &projectionA;
}
}
else
returnValProducer = (projectionConsumers.done(curProjectionEdge = projectionConsumers.advance(curProjectionEdge))) ? 0 : &projectionConsumers.get(curProjectionEdge).getNode();
if (returnValProducer)
{
VirtualRegister* returnValVR;
// the Call defines a temporary register, which is precolored to
// the appropriate return register
returnValVR = &inEmitter.defineTemporary(*this, 1);
switch (returnValProducer->getKind())
{
case vkInt: case vkAddr:
{
returnValVR->preColorRegister(kR3Color);
// now create a "buffer" copy between the precolored return register
// and make the Copy define the return value edge from the pkCall
Copy_I& copyInsn = *new(inPool) Copy_I(inDataNode, inPool);
inEmitter.useTemporaryVR(copyInsn, *returnValVR, 0);
inEmitter.defineProducer(*returnValProducer, copyInsn, 0);
break;
}
case vkLong:
assert(false);
break;
case vkFloat: case vkDouble:
assert(false);
break;
default:
assert(false);
}
}
else
getInstructionDefineBegin()[1].kind = udNone; // zero out the unused outgoing edge
DataConsumer* firstArgument;
DataConsumer* curArgument;
// incoming store
if (tHasIncomingStore)
inEmitter.useProducer(inDataNode->nthInputVariable(0), *this, 0); // -> mem
firstArgument = inDataNode->getInputsBegin() + tHasFunctionAddress + tHasIncomingStore;
if (tHasFunctionAddress)
{
assert(inFunc == NULL); // programmer error to specify a function address if this Call has a function address
if (tIsDynamic)
inEmitter.useProducer(inDataNode->nthInputVariable(1), *this, 1); // -> incoming address
else
mCalleeAddress = (TVector*) addressFunction(PrimConst::cast(inDataNode->nthInputVariable(1)).value.a);
}
else
mCalleeAddress = (TVector*) inFunc;
inEmitter.mAccumulatorTOC.addData(&mCalleeAddress, sizeof(TVector), mTOCOffset);
// move all arguments <= 8 words into registers, handle most of the stack passed arguments later
uint8 curFixedArg = 0; // number of words passes as fixed arguments
uint8 curFloatArg = 0; // number of words passed as float arguments
uint8 curTotalArgNumber = tHasIncomingStore + tIsDynamic; // use number, which starts at 1 after the store, if it exists
for (curArgument = firstArgument; curArgument < inDataNode->getInputsEnd(); curArgument++, curTotalArgNumber++)
{
VirtualRegister* vr;
switch (curArgument->getKind())
{
case vkInt:
case vkAddr:
if (curFixedArg <= 8)
{
if (curArgument->isConstant())
vr = &inEmitter.genLoadConstant_I(*inDataNode, curArgument->getConstant().i);
else
{
Copy_I& copyInsn = *new(inPool) Copy_I(inDataNode, inPool);
inEmitter.useProducer(curArgument->getVariable(), copyInsn, 0);
vr = &inEmitter.defineTemporary(copyInsn, 0);
}
inEmitter.useTemporaryVR(*this, *vr, curTotalArgNumber);
vr->preColorRegister(curFixedArg);
}
else
{
StD_FixedDestRegister<kStackRegister>& storeParam = *new(inPool) StD_FixedDestRegister<kStackRegister>(inDataNode, inPool, dfLwz, 24 + (curFixedArg + curFloatArg) * 4);
if (curArgument->isConstant())
{
VirtualRegister& vr = inEmitter.genLoadConstant_I(*inDataNode, curArgument->getConstant().i);
inEmitter.useTemporaryVR(storeParam, vr, 1);
}
else
inEmitter.useProducer(curArgument->getVariable(), storeParam, 1);
// have the store use the incoming store edge, and define a temporary outgoing edge
// make the call depend on this temporary outgoing store edge
inEmitter.useProducer(inDataNode->nthInputVariable(0), storeParam, 0);
inEmitter.useTemporaryOrder(*this, inEmitter.defineTemporaryOrder(storeParam, 0), curTotalArgNumber);
}
curFixedArg++;
break;
case vkFloat:
case vkDouble:
if (curFloatArg <= 13)
vr->preColorRegister(curFloatArg++);
else
assert(false);
break;
case vkLong:
assert(false);
break;
default:
assert(false);
}
}
// keep track of maximum words used
inEmitter.mMaxArgWords = PR_MAX(inEmitter.mMaxArgWords, curFixedArg + curFloatArg);
}
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic>
void Call<tHasIncomingStore, tHasOutgoingStore,tHasFunctionAddress, tIsDynamic>::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& inFormatter)
{
assert(!tIsDynamic);
uint32 *curPC = curPC = (uint32 *) inStart;
int32 branchOffset;
bool sameTOC = (mCalleeAddress->toc == inFormatter.mRealTOC->mGlobalPtr);
bool isStub = true; // callee is stub
if (!isStub && sameTOC && (uint32) mCalleeAddress->functionPtr < 0x3FFFFFF)
{
*curPC++ = kBla | ( (uint32) mCalleeAddress->functionPtr & 0x03FFFFFF);
*curPC++ = kNop;
}
else if (!isStub && sameTOC && canBePCRelative(inStart, (void*) mCalleeAddress, branchOffset))
{
*curPC++ = kBl | (branchOffset & 0x03FFFFFF);
*curPC++ = kNop;
}
else
{
// we can or the offset right into the bl instruction (because aa and lk nicely use the last 2 bits)
*curPC++ = kBl | (((uint32) inFormatter.mNextFreePostMethod - (uint32)inStart) & 0x03FFFFFF);
inFormatter.mNextFreePostMethod = (uint32*) formatCrossTocPtrGl(inFormatter.mNextFreePostMethod, mTOCOffset + inFormatter.mRealTOCOffset);
*curPC++ = makeDForm(32, 2, 1, 20); // stw rtoc, 20(sp)
}
}
inline void CallD_::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
uint32 *curPC = (uint32 *) inStart;
*curPC++ = kBl | (((uint32) getDynamicPtrGl(inStart, udToRegisterNumber(getInstructionUseBegin()[1])) - (uint32) inStart) & 0x03FFFFFF);
*curPC++ = makeDForm(32, 2, 1, 20); // stw rtoc, 20(sp)
}
#endif // _H_PPCCALLS