Initial check-in of ElectricalFire, a Java JIT compiler.

This commit is contained in:
fur%netscape.com 1998-12-03 21:10:47 +00:00
Родитель 1ebf1ebe4a
Коммит 4ca5cf5fca
589 изменённых файлов: 152328 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,194 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// Backend.cpp
//
// Scott M. Silver
//
// Translate a ControlGraph into native code
#if defined(DEBUG) && (defined(WIN32) || defined(USE_MESA)) && defined(IGVISUALIZE)
#define USE_VISUALIZER
#endif
#ifdef USE_VISUALIZER
#define IGVISUALIZE_ONLY(x) x
#include "IGVisualizer.h"
#else
#define IGVISUALIZE_ONLY(x)
#endif
#include "Backend.h"
#include "ControlGraph.h"
#include "JavaVM.h"
#define INCLUDE_EMITTER
#include "CpuInfo.h"
#include "RegisterAllocator.h"
#include "CodeGenerator.h"
#include "CGScheduler.h"
#include "NativeFormatter.h"
#include "FieldOrMethod.h"
#include "LogModule.h"
#if DEBUG_laurentm
#include "ControlNodeScheduler.h"
#endif
static void
explodeImmediatePrimitives(ControlGraph &cg);
#ifdef DEBUG_LOG
static void
printInstructions(LogModuleObject inLogObject, ControlNode& inControlNode);
static void
printInstructions(LogModuleObject inLogObject, ControlNode& inControlNode)
{
InstructionList& instructions = inControlNode.getInstructions();
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i))
{
instructions.get(i).printDebug(inLogObject);
UT_OBJECTLOG(inLogObject, PR_LOG_ALWAYS, ("\n"));
}
}
#endif
UT_DEFINE_LOG_MODULE(Backend);
void*
translateControlGraphToNative(ControlGraph& inControlGraph, Method& inMethod)
{
VirtualRegisterManager vrMan(inControlGraph.pool);
MdEmitter emitter(inControlGraph.pool, vrMan);
CodeGenerator codeGenerator(inControlGraph.pool, emitter);
// break out constants
explodeImmediatePrimitives(inControlGraph);
// * generate code
DoublyLinkedList<ControlNode>::iterator j;
for (j = inControlGraph.controlNodes.begin(); !inControlGraph.controlNodes.done(j); j = inControlGraph.controlNodes.advance(j))
{
ControlNode &cn = inControlGraph.controlNodes.get(j);
codeGenerator.generate(cn);
#ifdef PRINT_INSTRUCTIONS_BEFORE_REGALLOC
cn.printRef(UT_LOG_MODULE(Backend));
UT_SET_LOG_LEVEL(Backend, PR_LOG_DEBUG);
printInstructions(UT_LOG_MODULE(Backend), cn);
#endif
}
// If the debugger is enabled, generate pc2bci table
if (VM::debugger.getEnabled()) {
// Use an arbitrary number - needs to be set appropriately later
inMethod.getPC2Bci().setSize(1000);
}
// * register allocation
if (!inControlGraph.dfsListIsValid())
inControlGraph.dfsSearch();
if (!inControlGraph.lndListIsValid())
inControlGraph.lndSearch();
RegisterAllocator registerAllocator(inControlGraph.pool, inControlGraph.dfsList, inControlGraph.lndList, inControlGraph.nNodes, vrMan, emitter);
registerAllocator.allocateRegisters();
#ifdef PRINT_INSTRUCTIONS_AFTER_REGALLOC
for (j = inControlGraph.controlNodes.begin(); !inControlGraph.controlNodes.done(j); j = inControlGraph.controlNodes.advance(j))
{
ControlNode &cn = inControlGraph.controlNodes.get(j);
printInstructions(UT_LOG_MODULE(Backend), cn);
}
#endif
#ifdef NEW_CG_SCHEDULER
ControlNodeScheduler cns(inControlGraph.pool, inControlGraph.dfsList, inControlGraph.nNodes);
ControlNode** scheduledNodes = cns.getScheduledNodes();
#else // NEW_CG_SCHEDULER
ControlGraphScheduler cgs(inControlGraph, emitter);
ControlNode** scheduledNodes = cgs.scheduleNodes();
#endif // NEW_CG_SCHEDULER
// * output to memory
NativeFormatter formatter(emitter, scheduledNodes, inControlGraph.nNodes);
void* func = formatter.format(inMethod);
IGVISUALIZE_ONLY(codeGenerator.visualize();)
return (func);
}
//
// Transform all immediate operations into
// operations which no longer intern a constant
//
// For example:
//
// vi2 = AddI_I 6, vi1
//
// becomes
//
// vi1 = Const_I 6
// vi3 = Add_I vi1, vi2
//
static void
explodeImmediatePrimitives(ControlGraph &cg)
{
cg.dfsSearch();
ControlNode **dfsList = cg.dfsList;
ControlNode **pcn = dfsList + cg.nNodes;
while (pcn != dfsList)
{
ControlNode &cn = **--pcn;
// Search the primitives backwards; explode primitives as necessary
DoublyLinkedList<Primitive> &primitives = cn.getPrimitives();
DoublyLinkedList<Primitive>::iterator primIter = primitives.end();
while (!primitives.done(primIter))
{
Primitive &p = primitives.get(primIter);
primIter = primitives.retreat(primIter);
// loop through all consumers of p; if a consumer is constant create
// a new PrimConst node, and attach it to p
DataConsumer* input;
for (input = p.getInputsBegin(); input < p.getInputsEnd(); input++)
{
if (input->isConstant() && isRegOrMemKind(input->getKind()))
{
PrimConst *prim = new(cn.getPrimitivePool())
PrimConst(input->getKind(), input->getConstant(),
p.getBytecodeIndex());
input->setVariable(*prim);
cn.appendPrimitive(*prim);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// Backend.h
//
// Scott M. Silver
//
// Translate a ControlGraph into native code
#ifndef _H_BACKEND
#define _H_BACKEND
struct Method;
class ControlGraph;
void* translateControlGraphToNative(ControlGraph& inControlGraph, Method& inMethod);
#endif

Просмотреть файл

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
Burg.h
*/
// Burg needs these
#include <stdio.h>
#include <stdlib.h>
// Stuff that we use for burg
#include "CodeGenerator.h"
#include "Primitives.h"
typedef Primitive* NODEPTR_TYPE;
#define OP_LABEL(p) p->getOperation()
#define STATE_LABEL(p) p->getBurgState()
#define SET_STATE_LABEL(p, state) p->setBurgState(state)
#define LEFT_CHILD(p) CodeGenerator::getExpressionLeftChild(p)
#define RIGHT_CHILD(p) CodeGenerator::getExpressionRightChild(p)
#define PANIC printf
extern short *burm_nts[];
extern char *burm_string[];
extern char * burm_opname[];
extern char burm_arity[];
extern short burm_cost[][4];
extern char *burm_ntname[];
// burgs exported functions
int burm_rule(int state, int goalnt);
int burm_state(int op, int l, int r);
int burm_label(NODEPTR_TYPE n);
NODEPTR_TYPE * burm_kids(NODEPTR_TYPE p, int rulenumber, NODEPTR_TYPE *kids);
NODEPTR_TYPE burm_child(NODEPTR_TYPE p, int index);
int burm_op_label(NODEPTR_TYPE p);
int burm_state_label(NODEPTR_TYPE p);

Просмотреть файл

@ -0,0 +1,222 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "CGScheduler.h"
#include "ControlGraph.h"
#include "InstructionEmitter.h"
#include "GraphUtils.h"
inline static bool
isPredecessor(ControlNode& pred, ControlNode& node)
{
ControlEdge* limit = pred.getSuccessorsEnd();
for (ControlEdge* ptr = pred.getSuccessorsBegin(); ptr < limit; ptr++)
if (&ptr->getTarget() == &node)
return true;
return false;
}
ControlNode** ControlGraphScheduler::
scheduleNodes()
{
ControlNode** orderedNodes = orderNodes();
addAbsoluteBranches(orderedNodes);
return orderedNodes;
}
// addAbsoluteBranches
// Given an ordering of ControlNodes in the graph add necessary
// implicit branches demanded by the ordering (ie to satisfy the ControlEdges)
void ControlGraphScheduler::
addAbsoluteBranches(ControlNode** orderedNodes)
{
Uint32 nNodes = cg.nNodes;
// for each ControlNode in orderedNodes, determine for each sequential pairing
// if a falls through to b then don't add an absolute branch from a->b, otherwise
// if the edge a->b does not exist, then add an absolute branch to where a should
// connect.
for (Uint32 n = 0; n < nNodes; n++)
{
ControlNode* thisNode = orderedNodes[n];
ControlNode* nextNode = (n < (nNodes - 1)) ? orderedNodes[n+1] : (ControlNode *) 0;
ControlEdge* branchEdge;
switch(thisNode->getControlKind())
{
case ckIf:
case ckBlock:
case ckExc:
case ckAExc:
case ckCatch:
case ckBegin:
branchEdge = &thisNode->nthSuccessor(0);
break;
// these three ControlNodes never have any implicit branches
case ckSwitch:
case ckReturn:
case ckEnd:
case ckThrow:
branchEdge = NULL;
break;
default:
assert(false);
}
if (branchEdge != NULL && nextNode != NULL && &branchEdge->getTarget() != nextNode)
emitter.pushAbsoluteBranch(branchEdge->getSource(), branchEdge->getTarget());
}
}
ControlNode** ControlGraphScheduler::
orderNodes()
{
Uint32 nNodes = cg.nNodes - 1;
Uint32 myGeneration = ControlNode::getNextGeneration();
ControlNode** nodes = new ControlNode*[nNodes];
ControlNode** n_ptr = nodes;
SearchStackEntry<ControlEdge> *ceStack = new SearchStackEntry<ControlEdge>[nNodes];
SearchStackEntry<ControlEdge> *ceSp = ceStack;
ControlEdge beginEdge;
beginEdge.setTarget(cg.getBeginNode());
cg.getEndNode().generation = myGeneration;
ControlEdge* n = &beginEdge;
ControlEdge* l = &beginEdge + 1;
while(true)
{
if (n == l)
{
if (ceSp == ceStack)
break;
--ceSp;
n = ceSp->next;
l = ceSp->limit;
}
else
{
ControlNode& node = n++->getTarget();
if (node.generation != myGeneration)
{
node.generation = myGeneration;
node.schedulePos = Uint32(n_ptr - nodes);
*n_ptr++ = &node;
ceSp->next = n;
ceSp->limit = l;
ceSp++;
n = node.getSuccessorsBegin();
l = node.getSuccessorsEnd();
}
}
}
#ifndef WIN32 // ***** Visual C++ has a bug in the code for delete[].
delete ceStack;
#endif
Uint32* cnStack = new Uint32[nNodes];
Uint32* cnSp = cnStack;
ControlNode** orderedNodes = new(cg.pool) ControlNode*[nNodes + 1];
n_ptr = orderedNodes;
Uint32 next;
#if DEBUG
fill_n(orderedNodes, nNodes, (ControlNode *) 0);
#endif
myGeneration = ControlNode::getNextGeneration();
orderedNodes[nNodes] = &cg.getEndNode();
orderedNodes[nNodes]->generation = myGeneration;
*n_ptr++ = nodes[0];
*cnSp++ = 0;
next = 1;
while (true)
{
if (next == 0)
{
if (cnSp == cnStack)
break;
next = *--cnSp;
}
else
{
ControlNode& node = *nodes[next];
if (node.generation == myGeneration)
{
next = 0;
}
else
{
// if (node.hasControlKind(ckIf))
const DoublyLinkedList<ControlEdge>& edges = node.getPredecessors();
if (!edges.done(edges.advance(edges.begin()))) // more than one predecessor
{
for (DoublyLinkedList<ControlEdge>::iterator i = edges.begin(); !edges.done(i); i = edges.advance(i))
{
ControlNode& source = edges.get(i).getSource();
if ((source.dfsNum > node.dfsNum) && (source.generation != myGeneration))
{
*cnSp++ = next;
next = source.schedulePos;
while (isPredecessor(*nodes[next - 1], *nodes[next]) &&
(nodes[next - 1]->generation != myGeneration) && (next != node.schedulePos))
next--;
break;
}
}
if (next == node.schedulePos)
{
node.generation = myGeneration;
*n_ptr++ = &node;
if (++next >= nNodes)
next = 0;
}
}
else
{
node.generation = myGeneration;
*n_ptr++ = &node;
if (++next >= nNodes)
next = 0;
}
}
}
}
//delete cnStack;
//delete [] nodes;
#if DEBUG
for (Uint32 i = 0; i < nNodes + 1; i++)
assert(orderedNodes[i]);
#endif
return orderedNodes;
}

Просмотреть файл

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _CG_SCHEDULER_H_
#define _CG_SCHEDULER_H_
#include "Fundamentals.h"
#include "Pool.h"
class ControlGraph;
class ControlNode;
class InstructionEmitter;
class ControlGraphScheduler
{
protected:
ControlGraph& cg;
InstructionEmitter& emitter;
ControlNode** orderNodes();
void addAbsoluteBranches(ControlNode** orderedNodes);
public:
ControlGraphScheduler(ControlGraph& mCg, InstructionEmitter& mEmitter) : cg(mCg), emitter(mEmitter) {}
ControlNode** scheduleNodes();
};
#endif /* _CG_SCHEDULER_H_ */

Просмотреть файл

@ -0,0 +1,458 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// CodeGenerator.cpp
//
// Scott M. Silver
// Peter Desantis
//
// A code generator is a loose organization of code which
// finds roots in a given control node of BURG-labellable expression
// trees. The trees are labelled, and an emit routine is called
// for each labelled tree.
#define INCLUDE_EMITTER
#include "CpuInfo.h"
#include "Vector.h"
#include "Primitives.h"
#include "CodeGenerator.h"
#include "Burg.h"
#include "Scheduler.h"
#include "ControlNodes.h"
#include "InstructionEmitter.h"
#ifdef USE_VISUALIZER
#include "IGVisualizer.h"
#endif
// sFakeRegPrimitives
//
// A table of primitives which are used as the children
// of primitives which are defined to be leaves in a
// control node. They are indexed by DataKind, ie
// vkInt, etc...
//Primitive sFakeReg_V(coReg_V); // no such register
Primitive sFakeReg_I(coReg_I, 0);
Primitive sFakeReg_L(coReg_L, 0);
Primitive sFakeReg_F(coReg_F, 0);
Primitive sFakeReg_D(coReg_D, 0);
Primitive sFakeReg_P(coReg_A, 0);
Primitive sFakeReg_C(coReg_C, 0);
Primitive sFakeReg_M(coReg_M, 0); // no such register
//Primitive sFakeReg_T(coReg_T); // no such register
Primitive* sFakeRegPrimitives[nValueKinds] =
{
NULL, // no such register
&sFakeReg_I,
&sFakeReg_L,
&sFakeReg_F,
&sFakeReg_D,
&sFakeReg_P,
&sFakeReg_C,
&sFakeReg_M,
NULL // no such register
};
// This needs to be here because of header include problems.
CodeGenerator::CodeGenerator(Pool& inPool, MdEmitter& inEmitter) :
mPool(inPool),
mEmitter(inEmitter)
#ifdef USE_VISUALIZER
,mVisualizer(*(new IGVisualizer()))
#endif
{
}
// generate
//
// Emit argumetns for the begin node.
// Find all roots of trees in inControlNode
// Label each root
// Call the emitter to emit for each root
void CodeGenerator::
generate(ControlNode& inControlNode)
{
Vector<RootPair> roots;
// First find all the roots in this control node
findRoots(inControlNode, roots);
if (inControlNode.hasControlKind(ckBegin))
mEmitter.emitArguments(inControlNode.getBeginExtra());
else
{
// for each root label, and emit code
RootPair* curRoot;
for (curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
{
label(*(curRoot->root));
emit(curRoot->root, 1);
}
}
// schedule and output instructions
LinearInstructionScheduler scheduler;
scheduler.schedule(roots, inControlNode);
#ifdef IGVISUALIZE
mVisualizer.addRoots(roots);
#endif
}
#ifdef IGVISUALIZE
void CodeGenerator::
visualize()
{
mVisualizer.visualize();
}
#endif
// label
//
// Label the treee rooted at inPrimitive
void CodeGenerator::
label(Primitive& inPrimitive)
{
burm_label(&inPrimitive);
}
// emit
//
// Actually traverse the primitives and emit instructions
// once labelled.
void CodeGenerator::
emit(Primitive* p, int goalnt)
{
int eruleno = burm_rule(p->getBurgState(), goalnt);
short* nts = burm_nts[eruleno];
Primitive* kids[10];
int i;
if (eruleno == 0)
{
trespass("BURG matching -- no cover");
}
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
emit(kids[i], nts[i]);
mEmitter.emitPrimitive(*p, eruleno);
}
// instructionUseToInstruction
//
// Move to the definer of this use.
//
// There are three cases.
//
// 1. If there is a defining Instruction
// in the Use, then that is the defining Instruction.
//
// 2. If the Use is Store or Cond Use, then if there is a
// defining Instruction then it will be attached to the
// DP at ID 0.
//
// 3. If the Use is a Register Use, then there must be some
// VR associated with the Use. The Instruction which defines
// the VR is the defining Instruction for this Use.
//
// It is possible that the result of 2 or 3 could be NULL after
// emitting for a given ControlNode. This means that the resource
// (outgoing edge) has not been defined, and is in another ControlNode.
// (or there was a programmer error, how do we detect which one)
Instruction* CodeGenerator::
instructionUseToInstruction(InstructionUse& inIUse)
{
Instruction* nextInsn;
if (inIUse.src != NULL)
nextInsn = inIUse.src;
else
{
switch (inIUse.kind)
{
case udStore: case udCond:
if (inIUse.name.dp != NULL)
{
if (inIUse.name.dp->getInstructionAnnotation() != NULL)
nextInsn = inIUse.name.dp->getInstructionAnnotation();
else
nextInsn = NULL;
}
else
nextInsn = NULL;
break;
case udRegister:
//assert(inIUse.name.vr); can't check this because it's a VR Pointer
nextInsn = inIUse.name.vr.getVirtualRegister().getDefiningInstruction();
break;
case udNone:
nextInsn = NULL;
break;
case udOrder:
nextInsn = inIUse.name.instruction;
break;
case udUninitialized:
assert(false);
default:
assert(false);
}
}
return (nextInsn);
}
// getExpressionLeftChild
//
// The BURG implementation of LEFT_CHILD
Primitive* CodeGenerator::
getExpressionLeftChild(Primitive* inPrimitive)
{
assert(inPrimitive);
bool hasIncomingStore = inPrimitive->hasCategory(pcLd) || inPrimitive->hasCategory(pcSt) || inPrimitive->hasCategory(pcCall);
DataConsumer* leftConsumer = &inPrimitive->nthInput(hasIncomingStore);
return (consumerToPrimitive(inPrimitive, leftConsumer));
}
// getExpressionRightChild
//
// Grab the right child of inPrimitive, skip over store edges
// [The BURG implementation of RIGHT_CHILD]
Primitive* CodeGenerator::
getExpressionRightChild(Primitive* inPrimitive)
{
assert(inPrimitive);
DataConsumer* rightConsumer;
bool hasIncomingStore = inPrimitive->hasCategory(pcLd) || inPrimitive->hasCategory(pcSt) || inPrimitive->hasCategory(pcCall);
rightConsumer = &inPrimitive->nthInput(1 + hasIncomingStore);
return (consumerToPrimitive(inPrimitive, rightConsumer));
}
// consumerToPrimitive
//
// Takes a consumer of a value and finds the primitive which produces
// the value that is consumed.
//
// an example:
//
// isLeaf
//
// child parent
// P2 pr <-> co P1
//
// co: inConsumer
// P1: inPrimitive
//
// co is a leaf edge if
//
// 1. co and pr (or P1 and P2) are in different control nodes -> return fake reg primitive
// 2. P2 is a root -> return fake reg primitive
//
// else
//
// return P2
Primitive* CodeGenerator::
consumerToPrimitive(Primitive* inPrimitive, DataConsumer* inConsumer)
{
// if it's already a fake reg primitive it has no children
if (inPrimitive->getOperation() >= coReg_V && inPrimitive->getOperation() <= coReg_I)
return NULL;
else if (inConsumer->isConstant())
return (sFakeRegPrimitives[inConsumer->getKind()]);
DataNode& consumerChildNode = inConsumer->getVariable();
Primitive* consumerChildPrimitive;
// extract P2 as above
if (!consumerChildNode.hasCategory(pcPhi))
consumerChildPrimitive = &Primitive::cast(consumerChildNode);
else
return (sFakeRegPrimitives[inConsumer->getKind()]); // phi node
// now perform the check to see if this edge connects to a "leaf" edge
if (consumerChildPrimitive->getContainer() != inPrimitive->getContainer() ||
isRoot(*consumerChildPrimitive))
{
return (sFakeRegPrimitives[inConsumer->getKind()]);
}
else
return (consumerChildPrimitive);
}
// search through all primitives in a control node
// return a vector of all the roots of expression trees
void CodeGenerator::
findRoots(ControlNode& inControlNode, Vector<RootPair>& outRoots)
{
DoublyLinkedList<Primitive>& primitives = inControlNode.getPrimitives();
for (DoublyLinkedList<Primitive>::iterator i = primitives.begin(); !primitives.done(i); i = primitives.advance(i))
{
Primitive& prim = primitives.get(i);
RootKind root = isRoot(prim);
if ((root == rkRoot) || (root == rkPrimary))
{
RootPair newRoot;
newRoot.root = &prim;
//prim.setRoot(true);
if(root == rkPrimary)
newRoot.isPrimary = true;
else
newRoot.isPrimary = false;
outRoots.append(newRoot);
}
// root member of prim defaults to false
}
}
// 1. is a primitive which is a pcIfCond (if or switch) OR
// 2. is a primitive which is a pcResult OR
// 3. is a primitive all of whose outputs are in a different control node from its own OR
// 4. is an interior primitive whose inputs are shared by two primitives in the same (cse)
// 5. is a primitive connected to another pcCall/pcSysCall primitive
// In cases 1 2 3 the root is primary
RootKind CodeGenerator::
isRoot(Primitive& inPrimitive)
{
bool isAtleastRoot = false;
// 1 or 2
if (inPrimitive.hasCategory(pcIfCond) || inPrimitive.hasCategory(pcResult) ||
inPrimitive.hasCategory(pcSwitch))
goto isRoot_rkPrimary;
// 3
DataNode* curEdge;
isAtleastRoot = inPrimitive.hasCategory(pcSt) || inPrimitive.hasCategory(pcCall) || inPrimitive.hasCategory(pcSysCall);
// all dp's primitive's containers hooked to curEdge must not be in same control node as inPrimitive's container
for (curEdge = inPrimitive.getOutgoingEdgesBegin(); curEdge < inPrimitive.getOutgoingEdgesEnd(); curEdge++)
{
const DoublyLinkedList<DataConsumer>& consumers = curEdge->getConsumers();
for ( DoublyLinkedList<DataConsumer>::iterator curConsumer = consumers.begin();
!consumers.done(curConsumer);
curConsumer = consumers.advance(curConsumer))
{
ControlNode* curConsumerContainer; // container of parentNode
DataNode* node; // parentNode (node which consume's inPrimitive's input)
node = &consumers.get(curConsumer).getNode();
// can ignore LdV because it has another incoming edge
isAtleastRoot |= ((node->getOutgoingEdgesEnd() - node->getOutgoingEdgesBegin() > 1) ||
(node->hasCategory(pcCall) || node->hasCategory(pcSysCall)));
if (node->hasCategory(pcCall))
{
DataNode* calleeAddress = &node->nthInput(1).getVariable();
if (&inPrimitive == calleeAddress)
{
isAtleastRoot = false;
goto isRoot_rkNotRoot;
}
}
curConsumerContainer = node->getContainer();
if (!node->hasCategory(pcPhi) && curConsumerContainer == inPrimitive.getContainer())
{
// If there are any consumers in the current container, then the primitive is a root
// iff it produces a cse----look for another consumer in the primitive's container
// Continue looking through the curEdge
curConsumer = consumers.advance(curConsumer);
for ( ;
!consumers.done(curConsumer);
curConsumer = consumers.advance(curConsumer))
{
node = &consumers.get(curConsumer).getNode();
if (node->hasCategory(pcCall) || node->hasCategory(pcSysCall))
goto isRoot_rkRoot;
curConsumerContainer = node->getContainer();
if (curConsumerContainer == inPrimitive.getContainer()) // cse found.
goto isRoot_rkRoot;
}
curEdge++;
// Now continue looking through the other edges
for (;curEdge < inPrimitive.getOutgoingEdgesEnd(); curEdge++)
{
const DoublyLinkedList<DataConsumer>& consumers = curEdge->getConsumers();
for ( DoublyLinkedList<DataConsumer>::iterator thisConsumer = consumers.begin();
!consumers.done(thisConsumer);
thisConsumer = consumers.advance(thisConsumer))
{
node = &consumers.get(thisConsumer).getNode();
if (node->hasCategory(pcCall) || node->hasCategory(pcSysCall))
goto isRoot_rkRoot;
curConsumerContainer = node->getContainer();
if (curConsumerContainer == inPrimitive.getContainer()) // cse found
goto isRoot_rkRoot;
}
}
// We did not find a cse => not a root
goto isRoot_rkNotRoot;
}
}
}
// if we passed through the above loop, 3. must have been met (fall through to rkPrimary)
isRoot_rkPrimary:
return (rkPrimary);
isRoot_rkRoot:
return (rkRoot);
isRoot_rkNotRoot:
return (isAtleastRoot ? rkRoot : rkNotRoot);
}

Просмотреть файл

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// CodeGenerator.h
//
// Scott M. Silver
//
#ifndef CODEGENERATOR_H
#define CODEGENERATOR_H
#include "Vector.h"
#include "CpuInfo.h"
class Primitive;
class ControlNode;
class Pool;
class DataConsumer;
class Instruction;
struct InstructionUse;
#ifdef IGVISUALIZE
class IGVisualizer;
#endif
struct RenumberData
{
int neededVisits;
int timesVisited;
bool renumbered;
};
// RootPair
struct RootPair
{
Primitive* root; // root of a BURG labellable subtree
bool isPrimary; // if this root is not reachable by any other root in
// this ControlNode
RenumberData data;
};
enum RootKind
{
rkNotRoot,
rkRoot,
rkPrimary
};
class CodeGenerator
{
protected:
Pool& mPool;
MdEmitter& mEmitter;
protected:
void label(Primitive& inPrimitive);
void emit(Primitive* p, int goalnt);
// roots, leaves
void findRoots(ControlNode& inControlNode, Vector<RootPair>& outRoots);
static RootKind isRoot(Primitive& inPrimitive);
public:
CodeGenerator(Pool& inPool, MdEmitter& inEmitter);
void generate(ControlNode& inControlNode);
// for BURG labeler
static Primitive* consumerToPrimitive(Primitive* inPrimitive, DataConsumer* inConsumer);
static Primitive* getExpressionLeftChild(Primitive* inPrimitive);
static Primitive* getExpressionRightChild(Primitive* inPrimitive);
static Instruction* instructionUseToInstruction(InstructionUse& inIUse);
// visualization
#ifdef IGVISUALIZE
public:
void visualize();
protected:
IGVisualizer& mVisualizer;
#endif
};
#endif // CODEGENERATOR_H

Просмотреть файл

@ -0,0 +1,748 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlNodes.h"
#include "ControlNodeScheduler.h"
#include "FastBitSet.h"
// ----------------------------------------------------------------------------
// LoopHierarchySet
//
// Create a new set of LoopHierachyNodes. Allocate the LoopHierarchyNode array of
// length nLoops and the indexes array of length nNodes in the given pool.
//
LoopHierarchySet::LoopHierarchySet(Pool& pool, LoopHierarchyNode* nodesArray, Uint32 nNodes) : nodes(nodesArray)
{
indexes = new(pool) Int32[nNodes];
nextFree = 0;
fill(indexes, &indexes[nNodes], -1);
}
//
// Return the set's element corresponding to the ControlNode dfsNum equals nodeIndex.
//
LoopHierarchyNode& LoopHierarchySet::operator [] (const Uint32 nodeIndex)
{
Int32 index = indexes[nodeIndex];
// If index is -1 then this node is not part of the set yet.
if (index == -1) {
index = nextFree++;
indexes[nodeIndex] = index;
}
return nodes[index];
}
// ----------------------------------------------------------------------------
// ControlNodeScheduler
//
// Return true if node is ready. We will call a node N ready if each of its
// incoming edges E: A->N are long.
//
inline bool nodeIsReady(ControlNode& node)
{
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i))
if (!predecessors.get(i).longFlag)
return false;
return true;
}
//
// Return true if node is ready with respect to 'respect'. We will call a node N
// ready with respect to node P if, for each of N's incoming edges E: A->N, either
// E is long or A equals P.
//
inline bool nodeIsReadyWithRespectTo(ControlNode& node, ControlNode& respect)
{
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
ControlEdge& edge = predecessors.get(i);
if (!edge.longFlag && (&edge.getSource() != &respect))
return false;
}
return true;
}
//
// Schedule the working nodes in loopToSchedule.
//
void ControlNodeScheduler::scheduleLoop(LoopHierarchyNode& loopToSchedule)
{
#if defined(DEBUG_SCHEDULER)
fprintf(stdout, "ControlNodeScheduler: Will schedule loop headed by N%d\n", loopToSchedule.header);
#endif
//
// Determine the nodes in a region.
//
FastBitSet& REG = loopToSchedule.nodes; // REG is the region of nodes contained in this loop.
FastBitSet Rlocal(nNodes); // Rlocal is the set of nodes in REG that are not contained in any subloop of REG.
FastBitSet Rsubheaders(nNodes); // Rsubheaders is the set of headers of immediate subloops of REG.
FastBitSet Rcombined(nNodes); // Rcombined is the union of Rlocal and Rsubheaders.
FastBitSet R(nNodes); // R is the intersection of Rcombined and the set of all working nodes.
FastBitSet RR(nNodes); // RR is the intersection of REG and the set of all working nodes.
Rlocal = REG;
DoublyLinkedList<LoopHierarchyNode>& subLoops = loopToSchedule.getSuccessors();
for (DoublyLinkedList<LoopHierarchyNode>::iterator i = subLoops.begin(); !subLoops.done(i); i = subLoops.advance(i)) {
LoopHierarchyNode& subLoop = subLoops.get(i);
Rsubheaders.set(subLoop.header);
Rlocal -= subLoop.nodes;
}
Rcombined = Rlocal;
Rcombined |= Rsubheaders;
R = Rcombined;
RR = REG;
FastBitSet nonWorkingNodes(nNodes);
for (Int32 j = REG.firstOne(); j != -1; j = REG.nextOne(j))
if (!dfsList[j]->workingNode)
nonWorkingNodes.set(j);
R -= nonWorkingNodes;
RR -= nonWorkingNodes;
//
// Initialize long edge flag for each edge E: A->B for which at least one of A or B is in R
//
Uint32 generation = ControlNode::getNextGeneration();
for (Int32 j = R.firstOne(); j != -1; j = R.nextOne(j)) {
ControlNode& node = *dfsList[j];
ControlEdge* limit = node.getSuccessorsEnd();
for (ControlEdge* edge = node.getSuccessorsBegin(); edge != limit; edge++)
if (edge->getTarget().generation != generation)
initializeLongEdgeFlag(*edge, loopToSchedule, RR, Rlocal);
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
ControlEdge& edge = predecessors.get(p);
if (edge.getSource().generation != generation)
initializeLongEdgeFlag(edge, loopToSchedule, RR, Rlocal);
}
node.generation = generation;
}
//
// Linear scheduling.
//
FastBitSet W(nNodes); // W is the set of nodes in the region remaining to be scheduled.
W = R; // Initially W contains all nodes in R except the loop header.
W.clear(loopToSchedule.header); //
Clique** cliqueStack = new(pool) Clique*[nNodes]; // Stack of Cliques waiting to be scheduled.
Clique** cliqueStackPointer = cliqueStack; // Stack pointer.
Int32 P = loopToSchedule.header; // P is the last node scheduled. It is initially the loop header.
Int32 N; // Next node to schedule.
Clique* currentClique = new(pool) Clique();
currentClique->addLast(scheduledNodes[P]); // The loop header is always the first node of the first clique.
nodesAlreadyScheduled.set(P);
loopToSchedule.cliques.addLast(*currentClique);
while (!W.empty() || (cliqueStackPointer != cliqueStack)) {
// Alternative 1.
// If there exists a node N in W such that there exists at least one short edge from P to N
// and node N is ready with respect to P, then we pick any such node N to be the next node.
ControlNode& nodeP = *dfsList[P];
ControlEdge* limit = nodeP.getSuccessorsEnd();
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++) {
ControlNode& target = edge->getTarget();
if (!edge->longFlag && nodeIsReadyWithRespectTo(target, nodeP) && W.test(target.dfsNum)) {
N = target.dfsNum;
goto foundNextNode;
}
}
// Alternative 2.
// Otherwise, if the stack isn't empty, we pop a clique Ck from the stack, make it become the next clique of
// this region, make every edge from P to any node A remaining in W into a long edge, set P to be the
// last node of Ck, and continue with alternative 1 above.
if (cliqueStackPointer != cliqueStack) {
Clique* nextClique = *--cliqueStackPointer;
loopToSchedule.cliques.addLast(*nextClique);
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++)
if (W.test(edge->getTarget().dfsNum))
edge->longFlag = true;
P = nextClique->last().dfsNum;
currentClique = nextClique;
continue;
}
// Alternative 3.
// Otherwise, there must exist a node N in W such that node N is ready with respect to P.
// We pick any such node N to be the next node.
for (N = W.firstOne(); N != -1; N = W.nextOne(N))
if (nodeIsReadyWithRespectTo(*dfsList[N], *dfsList[P]))
goto foundNextNode;
PR_ASSERT(false); // Shouldn't happen.
foundNextNode:
// After we have picked node N, we remove N from the set W and make every edge
// from P to any node A remaining in W into a long edge.
W.clear(N);
for (ControlEdge* e = nodeP.getSuccessorsBegin(); e != limit; e++)
if (W.test(e->getTarget().dfsNum))
e->longFlag = true;
// If N is not the header of a subloop.
if (!Rsubheaders.test(N)) {
ControlNode& nodeN = *dfsList[N];
bool nodePhasEdgeToNodeN = false;
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++) {
if (&edge->getTarget() == &nodeN) {
// If there exists some edge from P to N then we append node N to the current
// clique in our region's schedule
nodePhasEdgeToNodeN = true;
currentClique->addLast(scheduledNodes[N]);
nodesAlreadyScheduled.set(N);
break;
}
}
if (!nodePhasEdgeToNodeN) {
// There is node edge from P to N. We start a new clique in this region
// and make N this clique's first node.
Clique* newClique = new(pool) Clique();
newClique->addLast(scheduledNodes[N]);
loopToSchedule.cliques.addLast(*newClique);
nodesAlreadyScheduled.set(N);
currentClique = newClique;
}
P = N;
} else { // N is the header of a subloop.
LoopHierarchyNode* subLoop = NULL;
// Find the clique of the subloop that contains node N.
DoublyLinkedList<LoopHierarchyNode>& subLoops = loopToSchedule.getSuccessors();
for (DoublyLinkedList<LoopHierarchyNode>::iterator i = subLoops.begin(); !subLoops.done(i); i = subLoops.advance(i)) {
subLoop = &subLoops.get(i);
if (subLoop->header == N)
break;
}
PR_ASSERT(subLoop);
Clique* subLoopClique = NULL;
for (DoublyLinkedList<Clique>::iterator c = subLoop->cliques.begin(); !subLoop->cliques.done(c); c = subLoop->cliques.advance(c)) {
bool foundClique = false;
subLoopClique = &subLoop->cliques.get(c);
for (DoublyLinkedList<ScheduledNode>::iterator n = subLoopClique->begin(); !subLoopClique->done(n); n = subLoopClique->advance(n))
if (subLoopClique->get(n).dfsNum == N) {
foundClique = true;
break;
}
if (foundClique)
break;
}
PR_ASSERT(subLoopClique);
ControlNode& nodeN = *dfsList[N];
bool nodePhasEdgeToNodeN = false;
// If N is the first node of the subloop's clique and there exists some edge from P to N then we append
// the entire clique to the current clique. Otherwise, we start a new clique and make the subloop's
// clique become this new clique's beginning.
for (ControlEdge* edge = nodeP.getSuccessorsBegin(); edge != limit; edge++)
if (&edge->getTarget() == &nodeN) {
nodePhasEdgeToNodeN = true;
break;
}
if (!((subLoopClique->first().dfsNum == N) && nodePhasEdgeToNodeN)) {
currentClique = new(pool) Clique();
loopToSchedule.cliques.addLast(*currentClique);
}
for (DoublyLinkedList<ScheduledNode>::iterator s = subLoopClique->begin(); !subLoopClique->done(s);) {
ScheduledNode& node = subLoopClique->get(s);
s = subLoopClique->advance(s);
node.remove();
currentClique->addLast(node);
}
subLoopClique->remove();
// If the subloop contained more than one clique, we push all remaining cliques onto the stack.
// We are carefull to keep the scheduling order.
for (DoublyLinkedList<Clique>::iterator t = subLoop->cliques.end(); !subLoop->cliques.done(t);) {
Clique& slc = subLoop->cliques.get(t);
t = subLoop->cliques.retreat(t);
slc.remove();
*cliqueStackPointer++ = &slc;
}
// The last node scheduled is the last node of the current clique.
P = currentClique->last().dfsNum;
}
}
//
// Loop scheduling
//
// Find the last clique in this region such that the last node N of this clique satisfies the following properties:
// 1.There exists an edge from N to H.
// 2.There are no short edges E: N->A for which A is outside R.
// 3.N is not a switch node.
// 4.N is not H.
for (DoublyLinkedList<Clique>::iterator c = loopToSchedule.cliques.end(); !loopToSchedule.cliques.done(c); c = loopToSchedule.cliques.retreat(c)) {
Clique& clique = loopToSchedule.cliques.get(c);
ControlNode& lastNode = *dfsList[clique.last().dfsNum];
bool hasEdgeToHeader = false;
bool noShortEdgeOutsiteR = true;
ControlEdge* limit = lastNode.getSuccessorsEnd();
for (ControlEdge* edge = lastNode.getSuccessorsBegin(); edge != limit; edge++) {
if (edge->getTarget().dfsNum == loopToSchedule.header)
hasEdgeToHeader = true;
if (!edge->longFlag && R.test(edge->getTarget().dfsNum))
noShortEdgeOutsiteR = false;
}
if (hasEdgeToHeader && noShortEdgeOutsiteR && (!lastNode.hasControlKind(ckSwitch)) && (lastNode.dfsNum != loopToSchedule.header)) {
// We found this clique. We remove the last node N of this clique and prepend it to this
// subloop's first clique. Now as long as this clique ends with some node N' that satisfies
// all of the properties below, we remove N' from the end of this clique and prepend it
// to this subloop's first clique.
//
// 1.There are no short edges E: N'->A for which A is outside R.
// 2.N' is not a switch node.
// 3.N' is not the loop's header.
ScheduledNode& sNode = scheduledNodes[lastNode.dfsNum];
sNode.remove();
loopToSchedule.cliques.first().addFirst(sNode);
for (DoublyLinkedList<ScheduledNode>::iterator n = clique.end(); !clique.done(n);) {
ControlNode& node = *dfsList[clique.get(n).dfsNum];
n = clique.retreat(n);
bool noShortEdgeOutsiteR = true;
ControlEdge* limit = node.getSuccessorsEnd();
for (ControlEdge* edge = node.getSuccessorsBegin(); edge != limit; edge++)
if (!edge->longFlag && R.test(edge->getTarget().dfsNum)) {
noShortEdgeOutsiteR = false;
break;
}
if (noShortEdgeOutsiteR && (!node.hasControlKind(ckSwitch)) && (node.dfsNum != loopToSchedule.header)) {
// The condition is satisfied.
ScheduledNode& sNode = scheduledNodes[lastNode.dfsNum];
sNode.remove();
loopToSchedule.cliques.first().addFirst(sNode);
}
else
break;
}
if (clique.empty())
clique.remove();
break;
}
}
#if defined(DEBUG_SCHEDULER)
fprintf(stdout, "done scheduled nodes: [ ");
for (DoublyLinkedList<Clique>::iterator x = loopToSchedule.cliques.begin(); !loopToSchedule.cliques.done(x); x = loopToSchedule.cliques.advance(x)) {
fprintf(stdout, "[ ");
Clique& clique = loopToSchedule.cliques.get(x);
for (DoublyLinkedList<ScheduledNode>::iterator z = clique.begin(); !clique.done(z); z = clique.advance(z))
fprintf(stdout, "N%d ", clique.get(z).dfsNum);
fprintf(stdout, "] ");
}
fprintf(stdout, "]\n");
#endif
}
//
// Set the long edge flag to the given edge in region.
//
void ControlNodeScheduler::initializeLongEdgeFlag(ControlEdge& edge, LoopHierarchyNode& inLoop, FastBitSet& RR, FastBitSet& Rlocal)
{
Int32 A = edge.getSource().dfsNum;
if (!RR.test(A)) { // Condition 1 - A is outside RR.
edge.longFlag = true;
return;
}
Int32 B = edge.getTarget().dfsNum;
if (A >= B) { // Condition 3 - edge is a backward edge.
edge.longFlag = true;
return;
}
if (edge.getSource().hasControlKind(ckSwitch)) { // Condition 4 - A is a switch node.
edge.longFlag = true;
return;
}
if (!Rlocal.test(A)) { // Condition 5 - A is in a subloop.
DoublyLinkedList<LoopHierarchyNode>& subLoops = inLoop.getSuccessors();
for (DoublyLinkedList<LoopHierarchyNode>::iterator l = subLoops.begin(); !subLoops.done(l); l = subLoops.advance(l)) {
LoopHierarchyNode& subLoop = subLoops.get(l);
if (subLoop.nodes.test(A)) { // subLoop is the largest inLoop's subloop that contains A.
for (DoublyLinkedList<Clique>::iterator c = subLoop.cliques.begin(); !subLoop.cliques.done(c); c = subLoop.cliques.advance(c))
if (subLoop.cliques.get(c).last().dfsNum == A) { // A is the last node of this clique.
edge.longFlag = false;
return;
}
// If we get there then A is not the last node of some cliques
edge.longFlag = true;
return;
}
}
}
if (!Rlocal.test(B)) { // Condition 6 - B is in a subloop.
DoublyLinkedList<LoopHierarchyNode>& subLoops = inLoop.getSuccessors();
for (DoublyLinkedList<LoopHierarchyNode>::iterator l = subLoops.begin(); !subLoops.done(l); l = subLoops.advance(l)) {
LoopHierarchyNode& subLoop = subLoops.get(l);
if (subLoop.nodes.test(B)) { // subLoop is the largest inLoop's subloop that contains B.
for (DoublyLinkedList<Clique>::iterator c = subLoop.cliques.begin(); !subLoop.cliques.done(c); c = subLoop.cliques.advance(c))
if (subLoop.cliques.get(c).last().dfsNum == B) { // B is the last node of this clique.
edge.longFlag = false;
return;
}
// If we get there then B is not the last node of some cliques
edge.longFlag = true;
return;
}
}
}
// Condition 2 - edge is any exception or return edge.
switch (edge.getSource().getControlKind()) {
case ckCatch: case ckEnd:
edge.longFlag = true;
return;
default:
break;
}
switch (edge.getTarget().getControlKind()) {
case ckCatch: case ckEnd:
edge.longFlag = true;
return;
default:
break;
}
edge.longFlag = false; // Condition 7.
}
//
// Fill the dominatorsMatrix with the dominators of all the nodes in this graph.
// Each row is a bitset of the dominators' dfsNum for the ControlNode which dfsNum is the row index.
// dominatorsMatrix must have (nNodes + 1) rows & nNodes columns. (One extra row is used for
// temporary calculations).
//
void ControlNodeScheduler::findDominators()
{
// Initially each ControlNode is dominated by all the other ControlNodes.
dominatorsMatrix.set();
// The Begin Node is initialized independently as it is only dominated by itself.
dominatorsMatrix.clearRow(0);
dominatorsMatrix.set(0, 0);
bool changed; // loop condition.
do {
changed = false;
for (Uint32 n = 1; n < nNodes; n++) {
dominatorsMatrix.setRow(nNodes);
// The dominators of a ControlNode are the intersection of the dominators of its
// predecessors plus itself.
const DoublyLinkedList<ControlEdge>& predecessors = dfsList[n]->getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i))
dominatorsMatrix.andRows(predecessors.get(i).getSource().dfsNum, nNodes);
dominatorsMatrix.set(nNodes, n);
if (!dominatorsMatrix.compareRows(nNodes, n)) {
changed = true;
dominatorsMatrix.copyRows(nNodes, n);
}
}
} while(changed);
}
//
// Find the loop headers in the given array of ControlNodes & return the number
// of headers found.
//
Uint32 ControlNodeScheduler::findLoopHeaders()
{
Uint32 nLoopHeaders = 0; // Number of loop headers in this graph.
findDominators();
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *dfsList[n];
Uint32 nodeIndex = node.dfsNum;
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
Uint32 predecessorIndex = predecessors.get(i).getSource().dfsNum;
// A loop header is a node with an incoming backward edge. This edge's source must be dominated
// by itself (called regular backward edge).
if ((predecessorIndex >= nodeIndex) && dominatorsMatrix.test(predecessorIndex, nodeIndex)) {
loopHeaders.set(nodeIndex);
nLoopHeaders++;
break;
}
}
}
if (!loopHeaders.test(0)) {
// The begin node is always considered to be a loop header (even if it's not).
loopHeaders.set(0);
nLoopHeaders++;
}
return nLoopHeaders;
}
//
// Build the LoopHierarchyTree, find the nodes for each loop and return the top of the tree.
//
LoopHierarchyNode& ControlNodeScheduler::buildLoopHierarchyTree()
{
Uint32* nodeStack = new(pool) Uint32[nNodes]; // Stack of nodes to look at.
Uint32 nLoopHeaders = findLoopHeaders();
LoopHierarchyNode* loopNodes = new(pool) LoopHierarchyNode[nLoopHeaders];
LoopHierarchySet loopSet(pool, loopNodes, nNodes); // Set of the loop headers in this graph.
// If the BeginNode is considered to be a loop then its body
// contains all the nodes in this graph.
LoopHierarchyNode& beginNode = loopSet[0];
beginNode.header = 0;
beginNode.nodes.sizeTo(pool, nNodes);
beginNode.nodes.set(0, nNodes - 1);
for (Int32 h = loopHeaders.nextOne(0); h != -1; h = loopHeaders.nextOne(h)) {
//
// Place this loop in the tree.
//
FastBitSet dominators(dominatorsMatrix.getRow(h), nNodes);
Int32 parent = h;
do // parent must be a loop header && this node must be included in the parent's loop nodes.
parent = dominators.previousOne(parent);
while (!(loopHeaders.test(parent) && loopSet[parent].nodes.test(h)));
loopSet[parent].addSuccessor(loopSet[h]);
//
// Find this loop's nodes.
//
Uint32* stackPointer = nodeStack;
LoopHierarchyNode& loop = loopSet[h];
// Initialize the loop header's variables.
loop.header = h;
loop.nodes.sizeToAndClear(pool, nNodes);
loop.nodes.set(h);
// Push the tails of this loop. Each tail must be dominated by the loop header.
const DoublyLinkedList<ControlEdge>& headerPredecessors = dfsList[h]->getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = headerPredecessors.begin(); !headerPredecessors.done(i); i = headerPredecessors.advance(i)) {
Uint32 predecessorIndex = headerPredecessors.get(i).getSource().dfsNum;
if ((predecessorIndex > Uint32(h)) && dominatorsMatrix.test(predecessorIndex, h)) {
loop.nodes.set(predecessorIndex);
*stackPointer++ = predecessorIndex;
}
}
while (stackPointer != nodeStack) {
Uint32 n = *--stackPointer;
const DoublyLinkedList<ControlEdge>& predecessors = dfsList[n]->getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator i = predecessors.begin(); !predecessors.done(i); i = predecessors.advance(i)) {
Uint32 predecessorIndex = predecessors.get(i).getSource().dfsNum;
if (!loop.nodes.test(predecessorIndex)) {
loop.nodes.set(predecessorIndex);
*stackPointer++ = predecessorIndex;
}
}
}
}
return loopSet[0];
}
//
// Return an array of scheduled nodes. This array has nNodes elements.
//
ControlNode** ControlNodeScheduler::getScheduledNodes()
{
// Initialize the ScheduledNodes.
scheduledNodes = new(pool) ScheduledNode[nNodes];
for (Uint32 i = 0; i < nNodes; i++) {
ScheduledNode& node = scheduledNodes[i];
node.dfsNum = i;
}
nodesAlreadyScheduled.sizeToAndClear(nNodes);
//
// Determine main nodes (called working nodes).
//
Uint32 generation = ControlNode::getNextGeneration();
Uint32* nodeStack = new(pool) Uint32[nNodes]; // Stack of nodes to look at.
Uint32* stackPointer = nodeStack;
*stackPointer++ = 0; // Push the beginNode.
while (stackPointer != nodeStack) {
Uint32 n = *--stackPointer;
ControlNode& node = *dfsList[n];
node.workingNode = true;
ControlEdge* limit = node.getSuccessorsEnd();
for (ControlEdge* edge = node.getSuccessorsBegin(); edge != limit; edge++) {
ControlNode& successor = edge->getTarget();
if (successor.generation != generation) {
switch(successor.getControlKind()) {
case ckCatch:
case ckEnd:
// We are not following the exception edges.
break;
default:
successor.generation = generation;
*stackPointer++ = successor.dfsNum;
break;
}
}
}
}
//
// Schedule the loops from the inside out.
//
struct EdgeStack
{
DoublyLinkedList<LoopHierarchyNode>* linkedList;
DoublyLinkedList<LoopHierarchyNode>::iterator position;
};
LoopHierarchyNode& top = buildLoopHierarchyTree();
EdgeStack *edgeStack = new(pool) EdgeStack[nNodes];
DoublyLinkedList<LoopHierarchyNode> edgeToBeginNodeList;
edgeToBeginNodeList.addLast(top);
DoublyLinkedList<LoopHierarchyNode>* currentList = &edgeToBeginNodeList;
DoublyLinkedList<LoopHierarchyNode>::iterator currentIterator = edgeToBeginNodeList.begin();
EdgeStack *edgeStackPointer = edgeStack;
while (true) {
if (currentList->done(currentIterator)) {
if (edgeStackPointer == edgeStack)
break;
--edgeStackPointer;
currentList = edgeStackPointer->linkedList;
currentIterator = edgeStackPointer->position;
// At this point all the loops below this one in the loop hierarchy tree have
// been scheduled.
LoopHierarchyNode& loopToSchedule = currentList->get(currentIterator->prev);
scheduleLoop(loopToSchedule);
} else {
LoopHierarchyNode& loop = currentList->get(currentIterator);
currentIterator = currentList->advance(currentIterator);
edgeStackPointer->linkedList = currentList;
edgeStackPointer->position = currentIterator;
edgeStackPointer++;
currentList = &loop.getSuccessors();
currentIterator = currentList->begin();
}
}
// FIXME: need to schedule the remaining nodes (exceptions).
// Summarize the scheduling.
ControlNode** result = new(pool) ControlNode*[nNodes];
ControlNode** ptr = result;
for (DoublyLinkedList<Clique>::iterator c = top.cliques.begin(); !top.cliques.done(c); c = top.cliques.advance(c)) {
Clique& clique = top.cliques.get(c);
for (DoublyLinkedList<ScheduledNode>::iterator s = clique.begin(); !clique.done(s); s = clique.advance(s))
*ptr++ = dfsList[clique.get(s).dfsNum];
}
// Add the endNode.
*ptr++ = dfsList[nNodes - 1];
PR_ASSERT(ptr == &result[nNodes]);
return result;
}

Просмотреть файл

@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _CONTROL_NODE_SCHEDULER_H_
#define _CONTROL_NODE_SCHEDULER_H_
#include "Fundamentals.h"
#include "Pool.h"
class ControlNode;
struct ScheduledNode : public DoublyLinkedEntry<ScheduledNode>
{
// A ScheduledNode must be a linked in the execution order to other ScheduledNode.
// As ControlNode is already a linked to other ControlNode in the graph we create
// an instance of this class for each ControlNode of the graph and copy the field dfsNum.
Int32 dfsNum;
};
class Clique : public DoublyLinkedList<ScheduledNode>, public DoublyLinkedEntry<Clique>
{
// A Clique is a linked list of ScheduledNode and also an entry in a linked list (list of Cliques in a loop).
};
class LoopHierarchyNode : public DoublyLinkedEntry<LoopHierarchyNode>
{
private:
DoublyLinkedList<LoopHierarchyNode> successors;
public:
Int32 header; // Loop header's dfsNum.
FastBitSet nodes; // Nodes contained in this loop.
DoublyLinkedList<Clique> cliques; // Linked list of Clique in this loop.
inline void addSuccessor(LoopHierarchyNode& successor) {successors.addLast(successor);}
inline DoublyLinkedList<LoopHierarchyNode>& getSuccessors() {return successors;}
};
class LoopHierarchySet
{
private:
LoopHierarchyNode* nodes; // Array of loop nodes in the loop hierarchy tree.
Int32* indexes; // Array of indexes of nodes in the dfs order.
Uint32 nextFree; // Next available slot in nodes.
LoopHierarchySet (const LoopHierarchySet &); // Copying forbidden
void operator = (const LoopHierarchySet &); // Copying forbidden
public:
LoopHierarchySet(Pool& pool, LoopHierarchyNode* nodesArray, Uint32 nNodes);
LoopHierarchyNode& operator[] (const Uint32 nodeIndex);
};
class ControlNodeScheduler
{
private:
Pool& pool;
ControlNode** dfsList; // List of ControlNodes in depth first search order (from the ControlGraph).
const Uint32 nNodes; // Number of ControlNodes in this graph.
FastBitMatrix dominatorsMatrix; // Matrix of dominators for all the ControlNodes.
FastBitSet loopHeaders; // BitSet of the loop headers in the graph.
FastBitSet nodesAlreadyScheduled; // BitSet of the ControlNodes currently scheduled.
ScheduledNode* scheduledNodes; // Array of ScheduledNodes. Used to chain the nodes in the Cliques.
LoopHierarchyNode& buildLoopHierarchyTree();
Uint32 findLoopHeaders();
void scheduleLoop(LoopHierarchyNode& loopToSchedule);
void initializeLongEdgeFlag(ControlEdge& edge, LoopHierarchyNode& inLoop, FastBitSet& RR, FastBitSet& Rlocal);
void findDominators();
public:
ControlNodeScheduler(Pool& p, ControlNode** nodes, Uint32 n) :
pool(p), dfsList(nodes), nNodes(n), dominatorsMatrix(n + 1, n), loopHeaders(n) {}
ControlNode** getScheduledNodes(); // Return the array of ControlNode in a scheduled order.
};
#endif /* _CONTROL_NODE_SCHEDULER_H_ */

Просмотреть файл

@ -0,0 +1,181 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// simon
//
#include "JavaVM.h"
#include "ExceptionTable.h"
#include "CatchAssert.h"
#include "LogModule.h"
UT_DEFINE_LOG_MODULE(ExceptionTable);
//-----------------------------------------------------------------------------------------------------------
// ExceptionTableBuilder
// METHOD addEntry
// In/Out: index -- created handler must be at or after stated index
// In newEntry -- entry to add to exception table
// Assumptions: entries must be added in ascending scheduled node order
void ExceptionTableBuilder::
addEntry(Uint32& index, ExceptionTableEntry& newEntry)
{
Uint32 tableSize = eTable.size();
// iterate through exception table trying to find an existing entry we can coalesce with
for(; index < tableSize; index++)
{
ExceptionTableEntry& ete = eTable[index];
// can't coalesce if handler, type or policy differ
if( (ete.pHandler != newEntry.pHandler) ||
(ete.pExceptionType != newEntry.pExceptionType))
continue;
// we require that the above noted assumption has been met
assert(ete.pEnd <= newEntry.pStart);
// extend range of existing exception table entry (coalesce) if possible
if(ete.pEnd == newEntry.pStart)
{
ete.pEnd = newEntry.pEnd; // coalesce ranges
#ifdef DEBUG_LOG
UT_LOG(ExceptionTable, PR_LOG_ALWAYS, ("merge"));
newEntry.print(UT_LOG_MODULE(ExceptionTable));
#endif
return; // index will point to index of table entry that was extended
}
}
// coalesce wasn't possible, so insert
eTable.append(newEntry);
#ifdef DEBUG_LOG
UT_LOG(ExceptionTable, PR_LOG_ALWAYS, ("add "));
newEntry.print(UT_LOG_MODULE(ExceptionTable));
#endif
// index will be correctly set from end of 'for' loop
}
//-----------------------------------------------------------------------------------------------------------
#ifdef DEBUG
// check important assumption that array is sorted and valid
// if it is not then nested trys will probably fail
void ExceptionTableBuilder::
checkInOrder()
{
if(eTable.begin() == eTable.end())
return;
ExceptionTableEntry *curr, *next, *last;
curr= eTable.begin();
last = eTable.end() - 1;
while(curr < last) {
next = curr + 1;
assert(curr->pStart <= curr->pEnd); // sanity check
assert(curr->pStart <= next->pStart); // ensure that items are sorted by pStart field
curr = next;
}
}
#endif // DEBUG
//-----------------------------------------------------------------------------------------------------------
// Constructor
// builds an exception table in the specified pool
ExceptionTable::
ExceptionTable(ExceptionTableBuilder eBuilder, Pool& inPool)
{
numberofEntries = eBuilder.getNumberofEntries();
start = eBuilder.start;
if(numberofEntries == 0)
{
mEntries = NULL;
}
else
{
Uint32 i;
mEntries = new(inPool) ExceptionTableEntry[numberofEntries];
for(i = 0; i < numberofEntries; i++)
mEntries[i] = eBuilder.getEntry(i);
Uint32 sz = eBuilder.getNumberofAPoints();
asynchPoints = new(inPool) Uint32[sz];
for(i = 0; i < sz; i++)
asynchPoints[i] = eBuilder.getAEntry(i);
}
}
// In: thrown object
// In: PC/EIP of
// Out: pointer to an ExceptionTableEntry that matches the thrown object (or NULL if no match)
ExceptionTableEntry*
ExceptionTable::
findCatchHandler(const Uint8* pc, const JavaObject& inObject)
{
const Class& clazz = inObject.getClass();
// scan through the handler list in _reverse_ looking for a match
// reverse scanning is needed to properly respect nested try blocks
if(numberofEntries > 0)
for(Int32 i = numberofEntries - 1; i >= 0; i--)
{
ExceptionTableEntry* tableEntry = mEntries + i;
if( (pc >= start + tableEntry->pStart) &&
(pc < start + tableEntry->pEnd) &&
clazz.implements( *(tableEntry->pExceptionType) ) )
return tableEntry;
}
return NULL;
}
//-----------------------------------------------------------------------------------------------------------
// DEBUG code
#ifdef DEBUG_LOG
void ExceptionTable::
print(LogModuleObject &f)
{
if(numberofEntries == 0)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("The exception table is empty.\n"));
}
else
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("(begin-offset, end-offset) -> handler-offset (exception caught)\n"));
for(Uint32 i = 0; i < numberofEntries; i++)
mEntries[i].print(f);
}
}
void ExceptionTable::
printShort(LogModuleObject &f)
{
if(numberofEntries != 0)
for(Uint32 i = 0; i < numberofEntries; i++)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\t"));
mEntries[i].print(f,start);
}
}
#endif // DEBUG

Просмотреть файл

@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// simon
//
#ifndef _EXCEPTION_TABLE_
#define _EXCEPTION_TABLE_
#include "Fundamentals.h"
#include "Vector.h"
#include "JavaObject.h"
#include "LogModule.h"
//-----------------------------------------------------------------------------------------------------------
// ExceptionTableEntry
class ExceptionTableEntry
{
public:
Uint32 pStart;
Uint32 pEnd; // offset to byte _after_ beginning of section
const Class* pExceptionType; // points to type of the handler
Uint32 pHandler;
#ifdef DEBUG_LOG
void print(LogModuleObject &f,Uint8* s)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("(%x,%x) -> %x (",Uint32(s+pStart), Uint32(s+pEnd), Uint32(s+pHandler)));
pExceptionType->printRef(f);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (")\n"));
}
void print(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("(%d,%d) -> %d (",Uint32(pStart), Uint32(pEnd), Uint32(pHandler)));
pExceptionType->printRef(f);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (")\n"));
}
#endif
};
//-----------------------------------------------------------------------------------------------------------
// ExceptionTableBuilder
class ExceptionTableBuilder
{
private:
Vector<ExceptionTableEntry> eTable;
Vector<Uint32> asynchPoints;
Uint8* start; // points to start of method
public:
ExceptionTableBuilder(Uint8* s) : eTable(), asynchPoints() { start = s; };
void addEntry(Uint32& index, ExceptionTableEntry& ete);
const ExceptionTableEntry& getEntry(Uint32 index) const { assert(index < eTable.size()); return (eTable[index]); }
Uint32 getNumberofEntries() const { return (eTable.size()); }
void addAEntry(Uint32 s) {
asynchPoints.append(s);
}
inline int getAEntry(int i) {
return asynchPoints[i];
}
inline int getNumberofAPoints() {
return asynchPoints.size();
}
friend class ExceptionTable;
DEBUG_ONLY(void checkInOrder());
};
//-----------------------------------------------------------------------------------------------------------
// ExceptionTable
class ControlNode;
class ExceptionTable
{
private:
Uint32 numberofEntries;
ExceptionTableEntry* mEntries;
int numberofAPoints;
Uint32* asynchPoints; // array of offsets for where the asynch. points are
Uint8* start; // points to start of method
static ClassFileSummary* excClass; // points to the class of RuntimeException
public:
ExceptionTable(ExceptionTableBuilder eBuilder, Pool& inPool);
ExceptionTableEntry* findCatchHandler(const Uint8* pc, const JavaObject& inObject);
Uint32 getNumberofEntries() { return numberofEntries; }
ExceptionTable(ExceptionTable& et) {
numberofEntries = et.numberofEntries;
mEntries = et.mEntries;
numberofAPoints = et.numberofAPoints;
asynchPoints = et.asynchPoints;
start = et.start;
}
ExceptionTable& operator=(Uint8* newstart)
{
start = newstart;
return *this;
}
inline Uint8* getStart() { return start; }
inline Uint32* getAsynchPoints() { return asynchPoints; }
inline int getNrOfAsynchPoints() { return numberofAPoints; }
static void staticInit(ClassCentral &central);
#ifdef DEBUG_LOG
void print(LogModuleObject &f);
void printShort(LogModuleObject &f);
void printFormatted(LogModuleObject &f, ControlNode** inNodes, Uint32 numNodes, bool isHTML);
#endif // DEBUG_LOG
};
struct ExceptionTableCache
{
ExceptionTable eTable;
JavaObject* exc;
ExceptionTableCache(ExceptionTable* et, Uint8* i, JavaObject* ex) : eTable(*et)
{
eTable = i; // relocates the table
exc = ex;
}
};
//-----------------------------------------------------------------------------------------------------------
#endif // _EXCEPTION_TABLE_

Просмотреть файл

@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: FormatStructures.h
//
// Authors: Simon Holmes a Court
//
// To avoid circular include problems, data structures used in the md emitter, md formatter
// and native formatter may be found here.
//
#ifndef _FORMAT_STRUCTURES_
#define _FORMAT_STRUCTURES_
#include "Fundamentals.h"
#include "LogModule.h"
struct Method;
class VirtualRegisterManager;
struct MethodDescriptor;
//-----------------------------------------------------------------------------------------------------------
// FormattedCodeInfo
struct FormattedCodeInfo
{
Method* method; // runtime descriptor of the method we're formatting
Uint8* methodStart; // ptr to beginning of allocated memory for the method
Uint8* methodEnd; // ptr to (FIX byte after?) end of allocated memory for the method
Uint32 prologSize;
Uint32 epilogSize;
Uint32 bodySize; // prologSize + epilogSize + formatted size of on the instructions in all ControlNodes
Uint32 preMethodSize;
Uint32 postMethodSize;
};
//-----------------------------------------------------------------------------------------------------------
// TVector
#ifdef GENERATE_FOR_PPC
#define USE_TVECTOR
#endif
#ifdef USE_TVECTOR
extern void* _MD_createTVector(const MethodDescriptor& inMethodDescriptor, void* inFunctionMemory);
#define M_MD_createTVector(inMethodDescriptor, inFunctionMemory) (_MD_createTVector(inMethodDescriptor, inFunctionMemory))
#else
#define M_MD_createTVector(inMethodDescriptor, inFunctionMemory) (inFunctionMemory)
#endif
//-----------------------------------------------------------------------------------------------------------
// StackFrameInfo
class StackFrameInfo
{
protected:
Uint8 numSavedGPRs;
Uint8 numSavedFPRs;
Uint8 numMonitorSlots;
Uint32 localStore_bytes;
DEBUG_ONLY(bool hasBeenInited;)
public:
StackFrameInfo() { DEBUG_ONLY(hasBeenInited = false); };
void init(VirtualRegisterManager& /*inVRManager*/) { DEBUG_ONLY(hasBeenInited = true); }
Uint32 getNumSavedGPRWords() { assert(hasBeenInited); return numSavedGPRs; }
Uint32 getNumSavedFPRWords() { assert(hasBeenInited); return numSavedFPRs; }
Uint32 getNumMonitorSlots() { assert(hasBeenInited); return numMonitorSlots; }
Uint32 getRegisterOffset() { assert(hasBeenInited); return numMonitorSlots; }
Uint32 getLocalStoreSizeBytes() { assert(hasBeenInited); return localStore_bytes; }
// x86 only right now!
// returns the offset (off EBP) to the beginning of the registers
Uint32 getCalleeSavedBeginOffset()
{
return localStore_bytes + 4;
}
// returns the offset (off EBP) to the stack pointer before any arguments are pushed
Uint32 getStackPointerOffset()
{
return localStore_bytes + (4 * numSavedGPRs) + (4 * numSavedFPRs) + (4 * numMonitorSlots);
}
#ifdef DEBUG_LOG
void print(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Policy: g%d:f%d:l%d\n", getNumSavedGPRWords(), getNumSavedFPRWords(), getLocalStoreSizeBytes()));
}
#endif // DEBUG_LOG
};
#endif // _FORMAT_STRUCTURES_

Просмотреть файл

@ -0,0 +1,508 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: HTMLMethodDump.cpp
// Author: Simon Holmes a Court
//
#include "Fundamentals.h"
#ifdef DEBUG_LOG
#include "LogModule.h"
#include "HTMLMethodDump.h"
#include "NativeFormatter.h"
#include "FieldOrMethod.h"
#include "ExceptionTable.h"
#include "ControlGraph.h"
#include <time.h>
//-----------------------------------------------------------------------------------------------------------
// Native Formatter method
UT_DEFINE_LOG_MODULE(MethodToHtml);
void dumpDissasembly(LogModuleObject &f, Uint8* start, Uint8* end)
{
if (end <= start) // this happens for the last node, or nodes without code
return;
Uint8* curAddr = start;
while ((curAddr != NULL) && (curAddr < end))
curAddr = (Uint8*) disassemble1(f, curAddr);
}
static void dumpHTMLByteCode(MethodToHTML output, Method* inMethod)
{
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n<br>\n"));
output.heading("ByteCode");
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n<br><blockquote>\n<pre>\n"));
inMethod->dumpBytecodeDisassembly(output.mFile);
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("</pre></blockquote>\n"));
}
static void dumpHTMLExceptionTable(MethodToHTML output, ExceptionTable& inExceptionTable, ControlNode** nodes, Uint32 nNodes)
{
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n<br>\n"));
output.heading("Exception Table");
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n<br><blockquote>\n<pre>"));
inExceptionTable.print(output.mFile);
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("</pre></blockquote>\n"));
inExceptionTable.printFormatted(output.mFile, nodes, nNodes, true);
}
void NativeFormatter::
dumpMethodToHTML(FormattedCodeInfo& fci, ExceptionTable& inExceptionTable)
{
// create and prepare the output file
MethodToHTML output;
output.mFile.setLogLevel(PR_LOG_ALWAYS);
output.mFile.setOptions(PR_LOG_OPTION_NIL);
assert(fci.method);
#if defined(XP_PC) || defined(LINUX)
if (*fci.methodStart == 0xcc)
fci.methodStart++;
#endif
// get clean name
const char* oldname = fci.method->getName();
char* name = new char[strlen(oldname) + 1];
strcpy(name, oldname);
char* q = name;
while(*q)
{
switch(*q)
{
case ':': case '<': case '>': case '/': case ' ':
*q = '_';
}
q++;
}
const char* filename = fci.method->getHTMLName();
// open file a clean filename
output.openFile(filename);
output.pageBegin(name);
// stats
const char* className = fci.method->getDeclaringClass()->getName();
output.statsBegin();
output.bigstatsLine("Name", name);
output.statsLine("Class/Name/Sig", className, name, fci.method->getSignatureString());
output.statsLine("Fully qualified name", fci.method->toString());
output.statsLine("HTML File Name", filename);
output.statsLine("Native Code Bytes", fci.methodEnd - fci.methodStart);
time_t currentTime; // output the time
time(&currentTime);
output.statsLine("Created", ctime(&currentTime));
output.statsEnd();
// disassemble bytecode
dumpHTMLByteCode(output, fci.method);
// disassemble
output.heading("Generated Code");
output.disassemblyTableBegin();
// dump prolog
Uint8* curOffset;
curOffset = fci.methodStart;
output.disassemblyRowBegin("Pre");
dumpDissasembly(output.mFile, curOffset, curOffset + fci.preMethodSize);
curOffset += fci.preMethodSize;
output.disassemblyColumnSeparator(0xeeeeee);
output.disassemblyColumnSeparator(0xdddddd);
output.disassemblyRowEnd();
output.disassemblyRowBegin("Pro");
dumpDissasembly(output.mFile, curOffset, curOffset + fci.prologSize);
curOffset += fci.prologSize;
output.disassemblyColumnSeparator(0xeeeeee);
output.disassemblyColumnSeparator(0xdddddd);
output.disassemblyRowEnd();
// dump methods
nodes[0]->controlGraph.dfsSearch();
nodes[0]->controlGraph.assignProducerNumbers(1);
// now go through and print out the high level representation (w/o prolog etc)
for (Uint32 n = 0; n < nNodes; n++)
{
ControlNode& node = *nodes[n];
output.disassemblyRowBegin(node.dfsNum);
// actual disassembly
Uint8* nodeStart;
Uint8* nodeEnd;
nodeStart = curOffset;
if (n != (nNodes - 1))
nodeEnd = fci.methodStart + nodes[n+1]->getNativeOffset();
else // last node
nodeEnd = fci.methodEnd;
curOffset = nodeEnd;
dumpDissasembly(output.mFile, nodeStart, nodeEnd);
output.disassemblyColumnSeparator(0xeeeeee);
// intended disassembly
InstructionList& instructions = node.getInstructions();
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i))
{
instructions.get(i).printPretty(output.mFile);
UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n"));
}
// primitive graph
output.disassemblyColumnSeparator(0xdddddd);
node.printPretty(output.mFile, 0);
output.disassemblyRowEnd();
}
output.disassemblyTableEnd();
// exception table
dumpHTMLExceptionTable(output, inExceptionTable, nodes, nNodes);
output.pageEnd();
output.closeFile();
// add this file reference to the index file
FileIndex::insertFile(filename, name, className);
FileIndex::output(); // FIX FIX FIX for now we output this file EVERY time we generate code
}
//-----------------------------------------------------------------------------------------------------------
FileIndex FileIndex::sFileIndex;
void FileIndex::
outputHelper()
{
// open the index file
FILE* f = fopen("index.html","w");
assert(f);
// print the header
fprintf(f, "<HTML>\n<HEAD>\n<TITLE>Generated Code Index</TITLE>\n</HEAD>\n"
"<BODY TEXT=#000000 BGCOLOR=#FFFFFF LINK=#FF0000 VLINK=#800080 ALINK=#0000FF>\n\n" );
// output links
ClassNode* c = classes;
while(c)
{
fprintf(f, "\n<br><B><FONT FACE=\"Arial,Helvetica\">%s</FONT></B><br>\n", c->className);
FileNode* n = c->files;
while(n)
{
fprintf(f, "\t<A HREF=\"%s\">%s</A><br>\n", n->fileName, n->methodName);
n = n->next;
}
c = c->next;
}
// output footers
fprintf(f, "\n</BODY>\n</HTML>\n");
fclose(f);
}
ClassNode* FileIndex::
findClassName(const char* className)
{
if(classes == NULL)
{
classes = new ClassNode(className);
return classes;
}
// search for a class object if there is one
ClassNode* foundClass = classes;
while(true)
{
if(strncmp(foundClass->className, className, 512) == 0)
return foundClass;
// no match, if end, make new node
if(foundClass->next == NULL)
{
foundClass->next = new ClassNode(className);
return foundClass->next;
}
else
foundClass = foundClass->next;
}
}
void FileIndex::
insertFileHelper(const char* inFileName, const char* inMethodName, const char* inClassName)
{
ClassNode* classnode = findClassName(inClassName);
FileNode* firstNode = classnode->files;
FileNode* newNode = new FileNode(inFileName, inMethodName);
if(firstNode == NULL)
{
classnode->files = newNode;
return;
}
// is it before the first?
if(strncmp(inMethodName, firstNode->methodName, 512) < 0)
{
classnode->files = newNode;
newNode->next = firstNode;
return;
}
// otherwise iterate through until we are after a node and then insert
FileNode* node = firstNode;
while(true)
{
if( node->next == NULL || // at end
(strncmp(inMethodName, node->next->methodName, 512) < 0) ) // lexically before next name
{
FileNode* tempNode = node->next;
node->next = newNode;
newNode->next = tempNode;
return;
}
node = node->next;
}
}
//-----------------------------------------------------------------------------------------------------------
// Debugging Code for outputting Exception Tables
static void tableBegin(LogModuleObject &f, bool isHTML)
{
if(isHTML)
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<BLOCKQUOTE>\n<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=0>\n"));
}
static void tableEnd(LogModuleObject &f, bool isHTML)
{
isHTML ? UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("</TABLE>\n</BLOCKQUOTE>\n")) : UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n\n\n"));
}
static void heading(LogModuleObject &f, Uint32 num, bool isHTML)
{
if(isHTML)
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TD WIDTH=20 BGCOLOR=#5b88f0 ALIGN=CENTER><B><FONT FACE=\"Arial,Helvetica\">%d</FONT></B></TD>", num));
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" %02d ", num));
}
static void rowBegin(LogModuleObject &f, bool isHTML)
{
if(isHTML)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TR><TD BGCOLOR=#5b88f0 WIDTH=50><B><FONT FACE=\"Arial,Helvetica\">Node</TD>"));
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TD BGCOLOR=#5b88f0 WIDTH=50><B><FONT FACE=\"Arial,Helvetica\">Offset</TD>"));
}
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N "));
}
static void nodeRowBegin(LogModuleObject &f, Uint32 node, Uint32 offset, bool isHTML)
{
if(isHTML)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TR><TD BGCOLOR=#eeeeee><B><FONT FACE=\"Arial,Helvetica\">N%d</TD>", node));
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TD ALIGN=RIGHT BGCOLOR=#dddddd>%d </FONT></B></TD>", offset));
}
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N%02d: %4d ", node, offset));
}
static void rowEnd(LogModuleObject &f, bool isHTML)
{
isHTML ? UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("</TR>\n")) : UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
}
static void printInside(LogModuleObject &f, bool isHTML)
{
isHTML ? UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TD BGCOLOR=#ff0000>&nbsp;</TD>")) : UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("| "));
}
static void printOutside(LogModuleObject &f, Uint32 col, bool isHTML)
{
if(isHTML)
if(col&1)
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TD BGCOLOR=#dddddd>&nbsp;</TD>"));
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("<TD BGCOLOR=#eeeeee>&nbsp;</TD>"));
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" "));
}
void ExceptionTable::
printFormatted(LogModuleObject &f, ControlNode** inNodes, Uint32 numNodes, bool isHTML)
{
Uint32 col;
if(numberofEntries == 0)
return;
// print headers
tableBegin(f, isHTML);
rowBegin(f, isHTML);
for(col = 0; col < numberofEntries; col++)
heading(f, col, isHTML);
rowEnd(f, isHTML);
// print table
for (Uint32 i = 0; i < numNodes; i++)
{
ControlNode* node = inNodes[i];
Uint32 pc = node->getNativeOffset();
nodeRowBegin(f, node->dfsNum, pc, isHTML);
for(col = 0; col < numberofEntries; col++)
if (pc >= mEntries[col].pStart && pc < mEntries[col].pEnd)
printInside(f, isHTML);
else
printOutside(f, col, isHTML);
rowEnd(f, isHTML);
}
tableEnd(f, isHTML);
}
//-----------------------------------------------------------------------------------------------------------
// Debugging Code for outputting HTML pages
void MethodToHTML::
openFile(const char* fileName)
{
// open the file
if (!mFile.setLogFile(fileName))
trespass("opening log file failed");
}
void MethodToHTML::
closeFile()
{
// assert(mFile);
// fclose(mFile);
}
void MethodToHTML::
pageBegin(const char* name)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n</HEAD>\n", name));
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<BODY TEXT=#000000 BGCOLOR=#FFFFFF LINK=#FF0000 VLINK=#800080 ALINK=#0000FF>\n\n"));
}
// Heading
void MethodToHTML::
heading(const char* label)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<B><FONT SIZE=+1 FACE=\"Arial,Helvetica\">%s</FONT></B><BR>\n", label));
}
// Stats
void MethodToHTML::
statsBegin()
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n<FONT SIZE=+2>\n<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 COLS=2>\n"));
}
void MethodToHTML::
statsLine(const char* label, const char* value)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TR><TD WIDTH=\"200\"><B>%s</B></TD><TD>%s</TD></TR>\n", label, value));
}
void MethodToHTML::
bigstatsLine(const char* label, const char* value)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TR>\n<TD WIDTH=\"200\"><B><FONT SIZE=+1 FACE=\"Arial,Helvetica\">%s</FONT></B></TD>\n"
"<TD><B><FONT SIZE=+1 FACE=\"Arial,Helvetica\">%s</FONT></B></TD>\n</TR>\n", label, value));
}
void MethodToHTML::
statsLine(const char* label, const int value)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TR><TD><B>%s</B></TD><TD>%d</TD></TR>\n", label, value));
}
void MethodToHTML::
statsLine(const char* label, const char* value1, const char* value2, const char* value3)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TR><TD WIDTH=\"200\"><B>%s</B></TD><TD>%s %s %s</TD></TR>\n", label, value1, value2, value3));
}
void MethodToHTML::
statsEnd()
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("</TABLE>\n</FONT>\n<BR>&nbsp;\n<BR>&nbsp;\n\n<A HREF=\"index.html\">go to index</A>\n<BR>&nbsp;\n<BR>&nbsp;\n\n"));
}
// disassembly
void MethodToHTML::
disassemblyTableBegin()
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=3 COLS=4 WIDTH=\"95%%\">\n<TR BGCOLOR=#5b88f0>\n"));
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TD WIDTH=50><CENTER><B><FONT FACE=\"Arial,Helvetica\">Node</FONT></B></CENTER></TD>\n"));
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TD><CENTER><B><FONT FACE=\"Arial,Helvetica\">Disassembly</FONT></B></CENTER></TD>\n"));
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TD><CENTER><B><FONT FACE=\"Arial,Helvetica\">Intended Code</FONT></B></CENTER></TD>\n"));
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("<TD><CENTER><B><FONT FACE=\"Arial,Helvetica\">Primitives</FONT></B></CENTER></TD>\n</TR>" ));
}
void MethodToHTML::
disassemblyRowBegin(Uint32 nodeNum)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n\n<TR>\n<TD ALIGN=CENTER VALIGN=TOP BGCOLOR=#eeeeee><A NAME=\"N%d\"><B><FONT FACE=\"Arial,Helvetica\">N%d</FONT></B></A>"
"</TD>\n<TD VALIGN=TOP BGCOLOR=#dddddd><PRE>", nodeNum, nodeNum));
}
void MethodToHTML::
disassemblyRowBegin(const char* label)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n\n<TR>\n<TD ALIGN=CENTER VALIGN=TOP BGCOLOR=#eeeeee><A NAME=\"%s\"><B><FONT FACE=\"Arial,Helvetica\">%s</FONT></B></A>"
"</TD>\n<TD VALIGN=TOP BGCOLOR=#dddddd><PRE>", label, label));
}
void MethodToHTML::
disassemblyColumnSeparator(Uint32 color)
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("&nbsp;</PRE></TD>\n\n<TD VALIGN=TOP BGCOLOR=#%06x><PRE>", color));
}
void MethodToHTML::
disassemblyRowEnd()
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("&nbsp;</PRE></TD>\n</TR>\n\n"));
}
void MethodToHTML::
disassemblyTableEnd()
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("</TABLE>\n\n"));
}
void MethodToHTML::
pageEnd()
{
UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n</BODY>\n</HTML>\n"));
}
//-----------------------------------------------------------------------------------------------------------
#endif // DEBUG_LOG

Просмотреть файл

@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: HTMLMethodDump.h
// Author: Simon Holmes a Court
//
#ifdef DEBUG_LOG
#include <fstream.h>
void dumpDissasembly(LogModuleObject &f, Uint8* start, Uint8* end);
//-----------------------------------------------------------------------------------------------------------
// Debugging Code for outputting HTML index
struct FileNode
{
const char* fileName;
const char* methodName;
FileNode* next;
FileNode(const char* inFileName, const char* inMethodName) :
fileName(inFileName), methodName(inMethodName), next(NULL) {};
};
struct ClassNode
{
const char* className;
FileNode* files; // pointers to files
ClassNode* next;
ClassNode(const char* inClassName) : className(inClassName), files(NULL), next(NULL) {};
};
// Object to store references to all the HTML files generated
class FileIndex
{
private:
ClassNode* classes;
FileIndex() : classes(NULL) {};
ClassNode* findClassName(const char* className);
void insertFileHelper(const char* fileName, const char* methodName, const char* className);
void outputHelper();
// FIX no destructor -- memory leak
public:
// static inline FileIndex& getFileIndex() { return (FileIndex::sFileIndex); };
static FileIndex sFileIndex;
static void output() { FileIndex::sFileIndex.outputHelper(); }
static void insertFile(const char* f, const char* m, const char* c) { FileIndex::sFileIndex.insertFileHelper(f, m, c); }
};
//-----------------------------------------------------------------------------------------------------------
// MethodToHTML
UT_EXTERN_LOG_MODULE(MethodToHtml);
class MethodToHTML
{
public:
LogModuleObject &mFile;
MethodToHTML() : mFile(UT_LOG_MODULE(MethodToHtml)) {}
// file stuff
void openFile(const char* fileName);
void closeFile();
// html to begin and end a page
void pageBegin(const char* name);
void pageEnd();
void heading(const char* label);
// statistics
void statsBegin();
void statsLine(const char* label, const char* value);
void statsLine(const char* label, const char* value1, const char* value2, const char* value3);
void statsLine(const char* label, const int value);
void bigstatsLine(const char* label, const char* value);
void statsEnd();
// dissassembly table
void disassemblyTableBegin();
void disassemblyRowBegin(Uint32 nodeNum);
void disassemblyRowBegin(const char* label);
void disassemblyColumnSeparator(Uint32 color);
void disassemblyRowEnd();
void disassemblyTableEnd();
};
#endif // DEBUG_LOG

Просмотреть файл

@ -0,0 +1,915 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
The instruction graph visulizer.
IGVisualizer.cpp
Peter DeSantis
*/
#if defined(DEBUG) && (defined(WIN32) || defined(USE_MESA)) && defined(IGVISUALIZE)
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>
#include "CodeGenerator.h"
#include "IGVisualizer.h"
#include "Instruction.h"
#include "Primitives.h"
#include "Vector.h"
// To allow glut callbacks to access member data
IGVisualizer* IGVisualizer::self = NULL;
IGVisualizer::
IGVisualizer()
{
font = GLUT_STROKE_ROMAN;
zoomFactor = 2;
cumZoom = 1;
objectCenterX = 0;
objectCenterY = 0;
mouseCenterX = 0;
mouseCenterY = 0;
nodeLocX = 0;
nodeLocY = 0;
xWindowDim = 800; // Dimension of window
yWindowDim = 600;
xDimGL = 10000;
yDimGL = 10000;
centerX = 0;
centerY = 0;
INSTRUCTIONWIDTH = 1400; // The size of the instruction itself
INSTRUCTIONHEIGHT = 500 ;
FRAMEWIDTH = 1450; // Frame is the area around an instruction
FRAMEHEIGHT = 750;
BORDERWIDTH = 20; // Border around an instruction
SPACEBETWEENTREES = 130;
ARGUMENTREGISTERS = 4; // VR <= AURGUMENTMENTREGISTERS
self = this;
roots = new Vector<VisualInstructionRoot>;
}
IGVisualizer ::
~IGVisualizer()
{
delete roots;
}
/*
Add all the roots you want to be visualized before calling visualize
*/
void IGVisualizer ::
addRoots(Vector<RootPair>& inRoots)
{
RootPair* curRoot;
VisualInstructionRoot* vRoot = NULL;
for(curRoot = inRoots.begin(); curRoot < inRoots.end(); curRoot++)
{
DataNode* curOutput;
Instruction* nextInsn;
if(curRoot->root->getOutgoingEdgesEnd() > curRoot->root->getOutgoingEdgesBegin())
{
// now walk through all vr's assigned to this producer
VirtualRegister* curVR;
for (curOutput = curRoot->root->getOutgoingEdgesBegin();
curOutput < curRoot->root->getOutgoingEdgesEnd();
curOutput++)
{
switch (curOutput->kind)
{
case vkCond:
case vkMemory:
nextInsn = curOutput->getInstructionAnnotation();
break;
default:
curVR = curOutput->getVirtualRegisterAnnotation();
assert (curVR);
nextInsn = curVR->getDefineInstruction();
break;
}
assert (nextInsn);
vRoot = new VisualInstructionRoot;
vRoot->root = nextInsn;
vRoot->exploringAsRoot = false;
vRoot->locAsCSE = new Vector<TreeLocation>;
vRoot->currentCSE = NULL;
vRoot->locAsRoot = NULL;
roots->append(*vRoot);
}
}
if (curRoot->root->getInstructionRoot() != NULL) {
nextInsn = curRoot->root->getInstructionRoot();
vRoot = new VisualInstructionRoot;
vRoot->root = nextInsn;
vRoot->exploringAsRoot = false;
vRoot->locAsCSE = new Vector<TreeLocation>;
vRoot->currentCSE = NULL;
vRoot->locAsRoot = NULL;
roots->append(*vRoot);
}
}
}
/*
Internal routine which visualizes the set of roots
*/
void IGVisualizer ::
visualizeRoots()
{
int bottom = 0;
int left = 0;
VisualInstructionRoot* curRoot;
for(curRoot = self->roots->begin(); curRoot < self->roots->end(); curRoot++)
{
curRoot->exploringAsRoot = true;
curRoot->locAsRoot = &DrawTree(*(curRoot->root), bottom, left);
bottom = curRoot->locAsRoot->top + self->SPACEBETWEENTREES;
curRoot->exploringAsRoot = false;
}
}
VisualInstructionRoot* IGVisualizer ::
isInRoots(Instruction* subRoot)
{
VisualInstructionRoot* curRoot;
for(curRoot = self->roots->begin(); curRoot < self->roots->end(); curRoot++)
if(curRoot->root == subRoot)
return curRoot;
return NULL;
}
/*
Internal routine to draw the tree rooted a root so that root's bottom is at yBottom
and the tree rooted at root extends to xLeft.
*/
TreeLocation& IGVisualizer ::
DrawTree(Instruction& root, int yBottom, int xLeft)
{
Instruction* subRoot;
InstructionUse* curUse;
TreeLocation* loc;
TreeLocation* myLocation = new TreeLocation;
Vector<TreeLocation> subTreeLocations;
VisualInstructionRoot* vRoot;
int left = xLeft;
int top = yBottom + self->FRAMEHEIGHT;
if(root.next == NULL)
{
assert(root.prev == NULL);
assert(root.getInstructionDefineEnd() == root.getInstructionDefineBegin() +1);
assert(root.getInstructionUseEnd() == root.getInstructionUseBegin() +1);
// Instruction has been removed from the list
curUse = root.getInstructionUseBegin();
subRoot = CodeGenerator::instructionUseToInstruction(*curUse);
if(subRoot != NULL)
{
vRoot = isInRoots(subRoot);
if(vRoot != NULL) // CSE
{
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + self->FRAMEHEIGHT;
loc->bottom = yBottom;
DrawSubExpressionNode(subRoot, loc->rootMiddle, loc->bottom);
vRoot->locAsCSE->append(*loc);
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + self->FRAMEHEIGHT;
loc->bottom = yBottom;
return *loc;
} else
{
PrimitiveOperation op = subRoot->getPrimitive()->getOperation();
switch (op)
{
case(poPhi_M):
case(poPhi_I):
case(poPhi_L):
case(poPhi_F):
case(poPhi_D):
case(poPhi_A):
case(poPhi_C):
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + self->FRAMEHEIGHT;
loc->bottom = yBottom;
DrawDummyNode(loc->rootMiddle, loc->bottom);
return *loc;
break;
default:
return DrawTree(*subRoot, yBottom, left);
break;
}
}
} else { // This input is not defined
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + self->FRAMEHEIGHT;
loc->bottom = yBottom;
if( (curUse->kind == udRegister) && ((*(curUse->name.vr)).index <= self->ARGUMENTREGISTERS) )
{
DrawArgumentNode(loc->rootMiddle, loc->bottom);
} else
DrawDummyNode(loc->rootMiddle, loc->bottom);
return *loc;
}
}
assert(root.prev != NULL);
// Draw your sub trees
for(curUse = root.getInstructionUseBegin(); curUse < root.getInstructionUseEnd(); curUse++)
{
subRoot = CodeGenerator::instructionUseToInstruction(*curUse);
if(subRoot != NULL)
{
vRoot = isInRoots(subRoot);
if(vRoot != NULL) // CSE
{
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + (2 * self->FRAMEHEIGHT);
loc->bottom = yBottom + self->FRAMEHEIGHT;
DrawSubExpressionNode(subRoot, loc->rootMiddle, loc->bottom);
vRoot->locAsCSE->append(*loc);
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + (2 * self->FRAMEHEIGHT);
loc->bottom = yBottom + self->FRAMEHEIGHT;
} else
{
PrimitiveOperation op = subRoot->getPrimitive()->getOperation();
switch (op)
{
case(poPhi_M):
case(poPhi_I):
case(poPhi_L):
case(poPhi_F):
case(poPhi_D):
case(poPhi_A):
case(poPhi_C):
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + (2 * self->FRAMEHEIGHT);
loc->bottom = yBottom + self->FRAMEHEIGHT;
DrawDummyNode(loc->rootMiddle, loc->bottom);
break;
default:
loc = &DrawTree(*subRoot, yBottom + self->FRAMEHEIGHT, left);
break;
}
}//loc = &DrawTree(*subRoot, yBottom + self->FRAMEHEIGHT, left);
}
else // This input is not defined
{
loc = new TreeLocation;
loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left;
loc->right = self->FRAMEWIDTH + left;
loc->top = yBottom + (2 * self->FRAMEHEIGHT);
loc->bottom = yBottom + self->FRAMEHEIGHT;
if( (curUse->kind == udRegister) && ((*(curUse->name.vr)).index <= self->ARGUMENTREGISTERS) )
{
DrawArgumentNode(loc->rootMiddle, loc->bottom);
} else
DrawDummyNode(loc->rootMiddle, loc->bottom);
}
if(loc->top > top)
top = loc->top;
left = loc->right;
subTreeLocations.append(*loc);
}
if(subTreeLocations.size() == 0)
{
myLocation->rootMiddle = (float)self->FRAMEWIDTH/2 + xLeft;
myLocation->right = self->FRAMEWIDTH + xLeft;
myLocation->top = yBottom + self->FRAMEHEIGHT;
myLocation->bottom = yBottom;
} else {
myLocation->rootMiddle = subTreeLocations.front().rootMiddle + (0.5f)*(subTreeLocations.back().rootMiddle - subTreeLocations.front().rootMiddle);
myLocation->right = subTreeLocations.back().right;
myLocation->top = top;
myLocation->bottom = yBottom;
}
DrawNode(myLocation->rootMiddle, yBottom, &root, subTreeLocations);
return *myLocation;
}
/*
Dum routine reads a file to a stream, returns size
printPretty should use strings
*/
int fileToString(char *fileName, char *string, int len)
{
FILE* file = fopen(fileName, "r");
assert(file);
char c = fgetc(file);
int i = 0;
while(!feof(file) && i < (len-1))
{
if(c == 9)
c = ' ';
string[i] = c;
i++;
c = fgetc(file);
}
string[i] = '\0';
fclose(file);
return i;
}
/*
Write instruction Name and label Registers
*/
void IGVisualizer ::
LabelNode(Instruction* inst)
{
FILE* file;
char fileName[] = "shitFile";
file = fopen(fileName, "w" );
char prettyString[50];
// Label instruction *****************************************
glColor3f(0.0, 0.0, 0.0);
glPushMatrix(); // 1
glTranslated(3*(float)self->BORDERWIDTH, (float)self->INSTRUCTIONHEIGHT/2.5, 0.0);
int len, i;
inst->printPretty(file);
fclose(file);
len = fileToString(fileName, prettyString, 50);
for (i = 0; i < len; i++)
{
glutStrokeCharacter(self->font, prettyString[i]);
}
glPopMatrix(); // 1
// Label Outputs *********************************************
glColor3f(0.5f, 0.2f, 0.4f);
char registerName[50];
float distanceBetween;
int vrn, j;
InstructionDefine* curDefine;
int numberOfOutputs, numberOfInputs;
numberOfOutputs= inst->getInstructionDefineEnd() - inst->getInstructionDefineBegin();;
assert(numberOfOutputs <= 1);
distanceBetween = (float)self->INSTRUCTIONWIDTH/(numberOfOutputs+1);
glPushMatrix(); // 2
glTranslatef(0.0, 3*(float)self->BORDERWIDTH, 0.0);
j=1;
for(curDefine = inst->getInstructionDefineBegin(); curDefine < inst->getInstructionDefineEnd(); curDefine++)
{
glPushMatrix(); // 3
glTranslatef(j*distanceBetween-100, 0.0, 0.0);
if(curDefine->kind == udRegister)
{
vrn = (*(curDefine->name.vr)).index;
sprintf(registerName, "R%d", vrn);
} else if (curDefine->kind == udCond)
sprintf(registerName, "Cond");
else
sprintf(registerName, "Store");
len = strlen(registerName);
for (i = 0; i < len; i++)
{
glutStrokeCharacter(self->font, registerName[i]);
}
glPopMatrix(); // 3
j++;
}
glPopMatrix(); // 2
// Label Inputs **********************************************
glColor3f(1.0f, 0.0f, 0.2f);
InstructionUse* curUse;
numberOfInputs = inst->getInstructionUseEnd() - inst->getInstructionUseBegin();
distanceBetween = (float)self->INSTRUCTIONWIDTH/(numberOfInputs+1);
glPushMatrix(); // 4
glTranslatef(0.0, self->INSTRUCTIONHEIGHT - 100 - 3*(float)self->BORDERWIDTH, 0.0);
j=1;
for(curUse = inst->getInstructionUseBegin(); curUse < inst->getInstructionUseEnd(); curUse++)
{
glPushMatrix(); // 5
glTranslatef(j*distanceBetween-100, 0.0, 0.0);
if(curUse->kind == udRegister)
{
vrn = (*(curUse->name.vr)).index;
sprintf(registerName, "R%d", vrn);
} else if (curUse->kind == udCond)
sprintf(registerName, "Cond");
else
sprintf(registerName, "Store");
len = strlen(registerName);
for (i = 0; i < len; i++)
{
glutStrokeCharacter(self->font, registerName[i]);
}
glPopMatrix(); // 5
j++;
}
glPopMatrix(); // 4
}
/*
Draw a single instruction with its bottom line centered at (xMiddle, yBottom)
*/
void IGVisualizer ::
DrawNode(double xMiddle, int yBottom, Instruction* inst, Vector<TreeLocation>& subTrees)
{
glPushMatrix(); // 1
glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0);
// Draw Instruction body *************************************
glColor3f(0.0, 1.0, 1.0);
glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT);
glColor3f(1.0, 1.0, 1.0);
glRecti(self->BORDERWIDTH, self->BORDERWIDTH, self->INSTRUCTIONWIDTH-self->BORDERWIDTH, self->INSTRUCTIONHEIGHT-self->BORDERWIDTH);
LabelNode(inst);
// Connect Inputs *************************************************
TreeLocation* loc;
int numberOfInputs = subTrees.size();
int distToNextLayer = self->FRAMEHEIGHT - self->INSTRUCTIONHEIGHT;
float jag = ((float)distToNextLayer/(numberOfInputs + 1));
float diffMid;
float distanceBetween = (float)self->INSTRUCTIONWIDTH/(numberOfInputs+1);
glPushMatrix(); // 2
glTranslatef(0.0, (float)self->INSTRUCTIONHEIGHT, 0.0);
int j=1;
for(loc = subTrees.begin(); loc < subTrees.end(); loc++)
{
glPushMatrix(); // 3
glTranslatef(j*distanceBetween, 0.0, 0.0);
diffMid = loc->rootMiddle - (float)xMiddle - (j*distanceBetween - ((0.5f)*self->INSTRUCTIONWIDTH));
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, j*jag);
glVertex2f(0.0f, j*jag);
glVertex2f(diffMid, j*jag);
glVertex2f(diffMid, j*jag);
glVertex2f(diffMid, (numberOfInputs + 1)*jag);
glEnd();
glPopMatrix(); // 3
j++;
}
glPopMatrix(); // 2
glPopMatrix(); // 1
}
/*
Draw a node as a subexpression
*/
void IGVisualizer ::
DrawSubExpressionNode(Instruction* inst, double xMiddle, double yBottom)
{
glPushMatrix(); // 1
glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0);
// Draw Instruction body *************************************
glColor3f(1.0, 1.0, 0.0);
glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT);
glColor3f(1.0, 1.0, 1.0);
glRecti(self->BORDERWIDTH, self->BORDERWIDTH, self->INSTRUCTIONWIDTH-self->BORDERWIDTH, self->INSTRUCTIONHEIGHT-self->BORDERWIDTH);
// Draw the node
LabelNode(inst);
glPopMatrix(); // 1
}
/*
Draw a dummy "unknown" instruction with its bottom line centered at (xMiddle, yBottom)
*/
void IGVisualizer ::
DrawDummyNode(double xMiddle, int yBottom)
{
char unknownMess[] = " ??? ";
glPushMatrix(); // 1
glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0);
// Draw Instruction body *************************************
glColor3f(1.0, 0.0, 0.0);
glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT);
glColor3f(1.0, 1.0, 1.0);
glRecti(5 * self->BORDERWIDTH, 5 * self->BORDERWIDTH, self->INSTRUCTIONWIDTH-(5*self->BORDERWIDTH), self->INSTRUCTIONHEIGHT-(5*self->BORDERWIDTH));
// Write Message ******************************************
glColor3f(1.0, 0.0, 0.0);
glPushMatrix(); // 2
glTranslated(3*(float)self->BORDERWIDTH, (float)self->INSTRUCTIONHEIGHT/2.5, 0.0);
int len, i;
len = (int) strlen(unknownMess);
for (i = 0; i < len; i++)
{
glutStrokeCharacter(self->font, unknownMess[i]);
}
glPopMatrix(); // 2
glPopMatrix(); //1
}
/*
Draw an argument node
*/
void IGVisualizer ::
DrawArgumentNode(double xMiddle, int yBottom)
{
char unknownMess[] = " Argument ";
glPushMatrix(); // 1
glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0);
// Draw Instruction body *************************************
glColor3f(0.0f, 1.0f, 0.3f);
glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT);
glColor3f(1.0f, 1.0f, 1.0f);
glRecti(5 * self->BORDERWIDTH, 5 * self->BORDERWIDTH, self->INSTRUCTIONWIDTH-(5*self->BORDERWIDTH), self->INSTRUCTIONHEIGHT-(5*self->BORDERWIDTH));
// Write Message ******************************************
glColor3f(0.0f, 1.0f, 0.3f);
glPushMatrix(); // 2
glTranslated(3*(float)self->BORDERWIDTH, (float)self->INSTRUCTIONHEIGHT/2.5, 0.0);
int len, i;
len = (int) strlen(unknownMess);
for (i = 0; i < len; i++)
{
glutStrokeCharacter(self->font, unknownMess[i]);
}
glPopMatrix(); // 2
glPopMatrix(); //1
}
/*
This is the window system specific stuff for setting up the window for gl.
Visualize is called only once and it enters a non-returning display loop.
*/
enum subMenuFields
{
findAsRoot,
findNextRef
};
void IGVisualizer :: visualize()
{
int zoomMenu, rootMenu;
char* argv ="myProgram";
int argc = 1;
// Initialization
glutInit(&argc, &argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(xWindowDim, yWindowDim);
glutCreateWindow("Instruction Graph Viewer Dulux");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-xDimGL, xDimGL, -yDimGL, yDimGL);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.0);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 1.0f);
// Add callbacks
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
// Create the menu
zoomMenu = glutCreateMenu(selectZoom);
glutAddMenuEntry("X 2", 2);
glutAddMenuEntry("X 5", 5);
rootMenu = glutCreateMenu(selectRoot);
glutAddMenuEntry("Goto Definition", findAsRoot);
glutAddMenuEntry("Goto Next Reference", findNextRef);
glutCreateMenu(mainMenu);
glutAddSubMenu("ZoomFactor", zoomMenu);
glutAddSubMenu("Explore Subexpression", rootMenu);
glutAddMenuEntry("Exit", 0);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
}
/*
The callback routines
*/
void IGVisualizer ::
display()
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix(); // 1
glScaled(self->cumZoom, self->cumZoom, 1);
glTranslated(self->centerX - self->objectCenterX + self->mouseCenterX, self->centerY - self->objectCenterY + self->mouseCenterY, 0);
visualizeRoots();
glPopMatrix(); // 1
glutSwapBuffers();
}
void IGVisualizer ::
selectZoom(int msg)
{
self->zoomFactor = float(msg);
glutPostRedisplay();
}
void IGVisualizer ::
selectRoot(int msg)
{
VisualInstructionRoot* vRoot = findRootAtLoc(self->nodeLocX, self->nodeLocY);
if(vRoot != NULL)
{
//printf("FOUND ONE\n");
switch(msg) {
case findAsRoot:
self->objectCenterX = vRoot->locAsRoot->rootMiddle;
self->objectCenterY = vRoot->locAsRoot->bottom;
self->mouseCenterX = 0;
self->mouseCenterY = 0;
break;
case findNextRef:
if(vRoot->currentCSE == NULL)
if(vRoot->locAsCSE->size() != 0)
vRoot->currentCSE = vRoot->locAsCSE->begin();
else
return;
else {
vRoot->currentCSE++;
if(vRoot->currentCSE == vRoot->locAsCSE->end())
vRoot->currentCSE = vRoot->locAsCSE->begin();
}
self->objectCenterX = vRoot->currentCSE->rootMiddle;
self->objectCenterY = vRoot->currentCSE->bottom;
self->mouseCenterX = 0;
self->mouseCenterY = 0;
break;
}
}
glutPostRedisplay();
}
VisualInstructionRoot* IGVisualizer ::
findRootAtLoc(double x, double y)
{
VisualInstructionRoot* vRoot;
TreeLocation* tree;
for(vRoot = self->roots->begin(); vRoot < self->roots->end(); vRoot++)
{
if(isInNode(x, y, vRoot->locAsRoot->rootMiddle, vRoot->locAsRoot->bottom))
return vRoot;
for(tree = vRoot->locAsCSE->begin(); tree < vRoot->locAsCSE->end(); tree++)
if(isInNode(x, y, tree->rootMiddle, tree->bottom))
return vRoot;
}
return NULL;
}
bool IGVisualizer ::
isInNode(double x, double y, double middle, int bottom)
{
if((x < (middle + (.5*self->INSTRUCTIONWIDTH))) && (x > (middle - (.5*self->INSTRUCTIONWIDTH))))
if((y > bottom) && (y < (bottom + self->INSTRUCTIONHEIGHT)))
return true;
return false;
}
void IGVisualizer ::
mainMenu(int msg)
{
switch(msg) {
case 0:
exit(0);
break;
}
glutPostRedisplay();
}
void IGVisualizer ::
mouse(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
double transX = -(x - (.5 * (self->xWindowDim)))*((2*self->xDimGL/self->xWindowDim)/self->cumZoom);
double transY = (y - (.5 * (self->yWindowDim)))*((2*self->yDimGL/self->yWindowDim)/self->cumZoom);
self->mouseCenterX = self->mouseCenterX + transX;
self->mouseCenterY = self->mouseCenterY + transY;
}
glutPostRedisplay();
}
void IGVisualizer ::
keyboard(unsigned char key, int x, int y)
{
switch(key){
case '+':
self->cumZoom = self->cumZoom * self->zoomFactor;
break;
case '-':
self->cumZoom = self->cumZoom / self->zoomFactor;
break;
case 's':
double transX = (x - (.5 * (self->xWindowDim)))*((2*self->xDimGL/self->xWindowDim)/self->cumZoom);
double transY = -(y - (.5 * (self->yWindowDim)))*((2*self->yDimGL/self->yWindowDim)/self->cumZoom);
//printf("mouse center**%f, %f**\n", self->mouseCenterX, self->mouseCenterY);
//printf("strans **%f, %f**\n", transX, transY);
//printf("obj center **%f, %f**\n", self->objectCenterX, self->objectCenterY);
self->nodeLocX = transX - self->mouseCenterX + self->objectCenterX;
self->nodeLocY = transY - self->mouseCenterY + self->objectCenterY;
//printf("node center **%f, %f**\n", self->nodeLocX, self->nodeLocY);
break;
}
glutPostRedisplay();
}
void IGVisualizer ::
reshape(int width, int height)
{
self->xWindowDim = width;
self->yWindowDim = height;
glViewport(0, 0, width, height);
glutPostRedisplay();
}
#endif

Просмотреть файл

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
The instruction graph visulizer.
IGVisualizer.h
Peter DeSantis
*/
#ifndef IGVISUALIZER
#define IGVISUALIZER
#if defined(DEBUG) && (defined(WIN32) || defined(USE_MESA)) && defined(IGVISUALIZE)
#include "CodeGenerator.h"
class Instruction;
class Vector;
struct TreeLocation
{
float rootMiddle;
int right;
int top;
int bottom;
};
struct VisualInstructionRoot
{
Instruction* root;
bool exploringAsRoot;
Vector<TreeLocation>* locAsCSE;
TreeLocation* currentCSE;
TreeLocation* locAsRoot;
};
class IGVisualizer
{
private:
void *font;
float zoomFactor;
double cumZoom;
double centerX, centerY;
double objectCenterX, objectCenterY;
double mouseCenterX, mouseCenterY;
double xDimGL, yDimGL;
double nodeLocX, nodeLocY;
int xWindowDim, yWindowDim;
int INSTRUCTIONWIDTH, INSTRUCTIONHEIGHT;
int FRAMEWIDTH, FRAMEHEIGHT;
int SPACEBETWEENTREES;
int BORDERWIDTH;
uint ARGUMENTREGISTERS;
static IGVisualizer* self;
Vector<VisualInstructionRoot>* roots;
static void visualizeRoots();
static TreeLocation& DrawTree(Instruction& root, int yBottom, int xLeft);
static void DrawNode(double xMiddle, int yBottom, Instruction* inst, Vector<TreeLocation>& subTrees);
static void DrawDummyNode(double xMiddle, int yBottom);
static void DrawArgumentNode(double xMiddle, int yBottom);
static VisualInstructionRoot* isInRoots(Instruction* root);
static void DrawSubExpressionNode(Instruction* inst, double xMIddle, double yBottom);
static void LabelNode(Instruction* inst);
static VisualInstructionRoot* findRootAtLoc(double x, double y);
static bool isInNode(double x, double y, double middle, int bottom);
public:
static void selectZoom(int msg);
static void selectRoot(int msg);
static void mainMenu(int msg);
static void mouse(int button, int state, int x, int y);
static void keyboard(unsigned char key, int x, int y);
static void reshape(int width, int height);
static void tick(void);
static void display();
void addRoots(Vector<RootPair>& roots);
void visualize();
IGVisualizer();
~IGVisualizer();
};
#endif //#if defined(DEBUG) && defined(WIN32) && defined(IGVISUALIZE)
#endif // IGVISUALIZER

Просмотреть файл

@ -0,0 +1,316 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
Instruction.cpp
Scott M. Silver
*/
#include "Instruction.h"
#include "Pool.h"
#include "InstructionEmitter.h"
Instruction::
Instruction(DataNode* inSrcPrimitive)
{
//DEBUG_ONLY(initialize());
DEBUG_ONLY(mDebug = 0xDEADBEEF);
mSrcPrimitive = inSrcPrimitive;
}
// unlinkRegisters
//
// remove all references to VirtualRegister
// for this Instruction.
void Instruction::
unlinkRegisters()
{
InstructionUse* use_limit = getInstructionUseEnd();
for(InstructionUse* use_ptr = getInstructionUseBegin(); use_ptr < use_limit; use_ptr++)
if (use_ptr->kind == udRegister)
use_ptr->name.vr.uninitialize();
InstructionDefine* def_limit = getInstructionDefineEnd();
for(InstructionDefine* def_ptr = getInstructionDefineBegin(); def_ptr < def_limit; def_ptr++)
if (def_ptr->kind == udRegister)
def_ptr->name.vr.uninitialize();
}
//#ifdef DEBUG
void Instruction::
initialize()
{
// clear out use's
InstructionUse* curUse;
for ( curUse = getInstructionUseBegin();
curUse < getInstructionUseEnd();
curUse++)
{
curUse[0].name.dp = NULL;
curUse[0].src = NULL;
curUse[0].kind = udUninitialized;
}
InstructionDefine* curDefine;
for ( curDefine = getInstructionDefineBegin();
curDefine < getInstructionDefineEnd();
curDefine++)
{
curDefine[0].name.dp = NULL;
curDefine[0].kind = udUninitialized;
}
}
//#endif
// addUse
//
//
void Instruction::
addUse(Uint8 inWhichInput, VirtualRegister& inVR, VirtualRegisterKind constraint)
{
InstructionUse* instructionUseBegin = getInstructionUseBegin();
assert(instructionUseBegin != NULL && getInstructionUseEnd() - inWhichInput > instructionUseBegin);
instructionUseBegin[inWhichInput].name.vr.initialize(inVR, constraint);
instructionUseBegin[inWhichInput].src = inVR.getDefiningInstruction();
instructionUseBegin[inWhichInput].kind = udRegister;
}
void Instruction::
addUse(Uint8 inWhichInput, DataNode& inProducer)
{
InstructionUse* instructionUseBegin = getInstructionUseBegin();
assert(instructionUseBegin != NULL && getInstructionUseEnd() - inWhichInput > instructionUseBegin);
assert(inProducer.hasKind(vkCond) || inProducer.hasKind(vkMemory));
instructionUseBegin[inWhichInput].name.dp = &inProducer;
if (inProducer.hasKind(vkCond))
instructionUseBegin[inWhichInput].kind = udCond;
else
instructionUseBegin[inWhichInput].kind = udStore;
}
void Instruction::
addUse(Uint8 inWhichInput, UseDefineKind inKind)
{
InstructionUse* instructionUseBegin = getInstructionUseBegin();
assert(instructionUseBegin != NULL && getInstructionUseEnd() - inWhichInput > instructionUseBegin);
instructionUseBegin[inWhichInput].name.dp = NULL;
instructionUseBegin[inWhichInput].kind = inKind;
}
void Instruction::
addUse(Uint8 inWhichInput, InstructionDefine& inUseOrder)
{
InstructionUse* instructionUseBegin = getInstructionUseBegin();
assert(instructionUseBegin != NULL && getInstructionUseEnd() - inWhichInput > instructionUseBegin);
instructionUseBegin[inWhichInput].name.instruction = inUseOrder.name.instruction;
instructionUseBegin[inWhichInput].kind = udOrder;
}
void Instruction::
addDefine( Uint8 inWhichOutput, VirtualRegister& inVR, VirtualRegisterKind constraint)
{
InstructionDefine* instructionDefineBegin = getInstructionDefineBegin();
assert(instructionDefineBegin != NULL && getInstructionDefineEnd() - inWhichOutput > instructionDefineBegin);
instructionDefineBegin[inWhichOutput].name.vr.initialize(inVR, constraint);
instructionDefineBegin[inWhichOutput].kind = udRegister;
}
void Instruction::
addDefine(Uint8 inWhichOutput, DataNode& inProducer)
{
InstructionDefine* instructionDefineBegin = getInstructionDefineBegin();
assert(instructionDefineBegin != NULL && getInstructionDefineEnd() - inWhichOutput > instructionDefineBegin);
assert(inProducer.hasKind(vkCond) || inProducer.hasKind(vkMemory));
if (inProducer.hasKind(vkCond))
instructionDefineBegin[inWhichOutput].kind = udCond;
else
instructionDefineBegin[inWhichOutput].kind = udStore;
}
void Instruction::
addDefine(Uint8 inWhichOutput, UseDefineKind inKind)
{
InstructionDefine* instructionDefineBegin = getInstructionDefineBegin();
assert(instructionDefineBegin != NULL && getInstructionDefineEnd() - inWhichOutput > instructionDefineBegin);
instructionDefineBegin[inWhichOutput].name.dp = NULL;
instructionDefineBegin[inWhichOutput].kind = inKind;
}
void Instruction::
addDefine(Uint8 inWhichOutput, InstructionDefine& /*inDefineOrder*/)
{
InstructionDefine* instructionDefineBegin = getInstructionDefineBegin();
assert(instructionDefineBegin != NULL && getInstructionDefineEnd() - inWhichOutput > instructionDefineBegin);
//instructionDefineBegin[inWhichOutput].name.instruction = this;
instructionDefineBegin[inWhichOutput].kind = udOrder;
}
void Instruction::
standardUseDefine(InstructionEmitter& inEmitter)
{
InstructionUse* instructionUseBegin = getInstructionUseBegin();
Uint8 curIndex;
standardDefine(inEmitter);
InstructionUse* curUse;
if (instructionUseBegin != NULL)
{
for (curUse = instructionUseBegin, curIndex = 0; curUse < getInstructionUseEnd(); curUse++, curIndex++)
{
addStandardUse(inEmitter, curIndex);
}
}
}
VirtualRegister* Instruction::
addStandardUse(InstructionEmitter& inEmitter, Uint8 curIndex)
{
assert (mSrcPrimitive != NULL);
return inEmitter.useProducer(mSrcPrimitive->nthInputVariable(curIndex), *this, curIndex);
}
void Instruction::
standardDefine(InstructionEmitter& inEmitter)
{
InstructionDefine* instructionDefineBegin = getInstructionDefineBegin();
Uint8 curIndex;
assert (mSrcPrimitive != NULL);
if (instructionDefineBegin != NULL)
{
InstructionDefine* curDefine;
for (curDefine = instructionDefineBegin, curIndex = 0; curDefine < getInstructionDefineEnd(); curDefine++, curIndex++)
{
assert(curIndex == 0);
inEmitter.defineProducer(*mSrcPrimitive, *this, curIndex);
//inEmitter.defineProducer(nthOutputProducer(*mSrcPrimitive, curIndex), *this, curIndex);
}
}
else
{
mSrcPrimitive->setInstructionRoot(this);
}
}
#ifdef DEBUG_LOG
void Instruction::
printDebug(LogModuleObject &f)
{
printPretty(f);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
// clear out use's
InstructionUse* curUse;
int i;
i=0;
for ( curUse = getInstructionUseBegin();
curUse < getInstructionUseEnd();
curUse++)
{
switch (curUse[0].kind)
{
case udRegister:
{
VirtualRegister& vReg = curUse[0].getVirtualRegister();\
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("u[%d]: %scolor = %d index = %d \n", i, vReg.isPreColored() ? "pre" : "", vReg.isPreColored() ?
vReg.getPreColor() : vReg.getColor(), vReg.getRegisterIndex()));
}
break;
default:
break;
}
i++;
}
InstructionDefine* curDefine;
i=0;
for ( curDefine = getInstructionDefineBegin();
curDefine < getInstructionDefineEnd();
curDefine++)
{
switch (curDefine[0].kind)
{
case udRegister:
{
VirtualRegister& vReg = curDefine[0].getVirtualRegister();
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("d[%d]: %scolor = %d index = %d\n", i, vReg.isPreColored() ? "pre" : "",
vReg.isPreColored() ? vReg.getPreColor() : vReg.getColor(), vReg.getRegisterIndex()));
}
break;
default:
break;
}
i++;
}
}
#endif
InsnUseXDefineYFromPool::
InsnUseXDefineYFromPool(DataNode* inSrcPrimitive, Pool& inPool, Uint8 inX, Uint8 inY) :
Instruction(inSrcPrimitive)
{
mX = inX;
mY = inY;
if (inX > 0)
mInsnUse = new(inPool) InstructionUse[inX];
else
mInsnUse = NULL;
if (inY > 0)
mDefineResource = new(inPool) InstructionDefine[inY];
else
mDefineResource = NULL;
initialize();
}

Просмотреть файл

@ -0,0 +1,272 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// Instruction.h
//
// Scott M. Silver
// Peter Desantis
// Laurent Morichetti
//
// Interface for schedulable and formattable instructions.
// Summary
//
// Instructions are medium weight representations of actual native instructions
// on a machine. They are manipulated for register allocation, scheduling
// and eventually to output themselves to memory.
//
// The ideas is that subclasses of Instruction (or one of the "helper" subclasses)
// are the basic unit of "cross-platform" manipulation. They contain
// all resources consumed or created (ie registers, memory, etc).
//
// Each instruction must implement a series of "interface" methods which
// are essentially queries, so that subsequent users of Instructions can
// make intelligent decision. (eg. whether an instruction is a call, so
// the register allocator can save non-volatiles)
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
#include "prtypes.h"
#include "Primitives.h"
#include "CpuInfo.h"
class Instruction;
class VirtualRegister;
class InstructionEmitter;
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊInstructionUse/Define ¥
#endif
// InstructionUseOrDefine is a class which represents the
// use or definition of a resource (either a store, cond, or
// register resource). Assigned to each use and define
// is a ResourceName which is the "name" of the resource
// being use, eg a virtual register. In addition InstructionUse's
// (not defines) contain (if available) the definer of the resource
// they are using. This is so that resources can be defined multiple
// times, but (data) dependencies remain accurate.
typedef enum
{
udNone = 0,
udUninitialized,
udStore,
udCond,
udOrder,
udRegister
} UseDefineKind;
struct ResourceName
{
VirtualRegisterPtr vr;
DataNode* dp;
Instruction* instruction;
};
struct InstructionUseOrDefine
{
UseDefineKind kind;
ResourceName name;
inline PRUint32 getRegisterIndex() { assert(isVirtualRegister()); return getVirtualRegister().getRegisterIndex(); }
inline VirtualRegister& getVirtualRegister() { assert(isVirtualRegister()); return (name.vr.getVirtualRegister()); }
inline VirtualRegisterPtr& getVirtualRegisterPtr() { assert(isVirtualRegister()); return (name.vr); }
inline bool isVirtualRegister() { return (kind >= udRegister); }
};
struct InstructionUse : InstructionUseOrDefine
{
Instruction* src;
Instruction& getDefiningInstruction() { return (*src); }
void setDefiningInstruction(Instruction& inInstruction) { src = &inInstruction; }
};
struct InstructionDefine : InstructionUseOrDefine
{
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊInstructionFlags ¥
#endif
// This is a bitmap of interesting things an instruction might do
typedef Uint16 InstructionFlags;
enum
{
ifNone = 0x0000, // default
ifModCC = 0x0001, // defines a condition edge (eg. cmp)
ifModStore = 0x0002, // modifies the store (eg. st)
ifCopy = 0x0004, // copies its uses to its defines (eg mov)
ifExternalInsn = 0x0008, // used by the register allocator to keep track of uses/defines outside of a function
ifCall = 0x0010, // makes a call - indicates that non-volatile registers should be saved before this instruction (eg call)
ifSpecialCall = 0x0020 // FIX-ME Laurent!!! If you ad a new flag please document it!!!
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊInstruction ¥
#endif
class Instruction :
public DoublyLinkedEntry<Instruction> // Inserted into a list of scheduled instructions
{
public:
Instruction(DataNode* inSrcPrimitive);
void addUse(Uint8 inWhichInput, VirtualRegister& inVR, VRClass cl = vrcInteger);
void addUse(Uint8 inWhichInput, DataNode& inProducer);
void addUse(Uint8 inWhichInput, UseDefineKind inKind);
void addUse(Uint8 inWhichInput, InstructionDefine& inUseOrder);
void addDefine(Uint8 inWhichOutput, DataNode& inProducer);
void addDefine(Uint8 inWhichOutput, VirtualRegister& inProducer, VRClass cl = vrcInteger);
void addDefine(Uint8 inWhichOutput, UseDefineKind inKind);
void addDefine(Uint8 inWhichOutput, InstructionDefine& inDefineOrder);
virtual InstructionUse* getInstructionUseBegin() = 0;
virtual InstructionUse* getInstructionUseEnd() = 0;
virtual InstructionDefine* getInstructionDefineBegin() = 0;
virtual InstructionDefine* getInstructionDefineEnd() = 0;
void standardUseDefine(InstructionEmitter& inEmitter);
virtual PRUint32* getExtraRegisterInterferenceBegin() { return NULL; } // what?? laurent-try again. other registers defined by this instruction.
virtual PRUint32* getExtraRegisterInterferenceEnd() { return NULL; }
inline const Uint16 getLineNumber() const { return (mSrcPrimitive->getLineNumber()); }
inline DataNode* getPrimitive() const { return( mSrcPrimitive); }
virtual InstructionFlags getFlags() const { return (ifNone); }
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return (0); }
virtual void formatToMemory(void * /*inStart*/, Uint32 /*inCurOffset*/, MdFormatter& /*inFormatter*/) { }
virtual bool switchUseToSpill(Uint8 /*inWhichUse*/, VirtualRegister& /*inVR*/) { return false; }
virtual bool switchDefineToSpill(Uint8 /*inWhichDefine*/, VirtualRegister& /*inVR*/) { return false; }
void unlinkRegisters(); // uninitialize the VirtualRegisterPtr for each use and define
virtual bool canSwitchToFormat(Uint32 /*mask*/) { return false; }
virtual void switchToFormat(Uint32 /*mask*/) {}
protected:
void standardDefine(InstructionEmitter& inEmitter);
VirtualRegister* addStandardUse(InstructionEmitter& inEmitter, Uint8 curIndex);
protected:
void initialize();
public:
#ifdef DEBUG_LOG
virtual void printPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("none")); }
virtual void printDebug(LogModuleObject &f);
#endif
#ifdef DEBUG
int mDebug;
#endif
#ifdef DEBUG // added by simon, FIX should remove
virtual void checkIntegrity() { };
virtual void printArgs() { };
#endif // DEBUG
protected:
DataNode* mSrcPrimitive; // the primitive from which this Instruction was generated
};
typedef DoublyLinkedList<Instruction> InstructionList;
// Comparator function for SortedDoublyLinkedList. To get the desired effects, we want to comparison function to
// return 1 if instruction a is of a great or equal line number then b. (ensures that later scheduled
// instructions of the same lineNumber end up later in the list. Also if the two instructions are the
// same, we want to return a 0. (Avoids duplicate scheduling)/
inline int instructionCompare(const Instruction* a, const Instruction* b)
{
assert(a != NULL && b != NULL);
if(a->getLineNumber() < b->getLineNumber())
return -1;
if(a == b)
return 0;
return 1;
}
class Pool;
class InsnUseXDefineYFromPool :
public Instruction
{
public:
InsnUseXDefineYFromPool(DataNode* inSrcPrimitive, Pool& inPool, Uint8 inX, Uint8 inY);
virtual InstructionUse* getInstructionUseBegin() { return (mInsnUse); }
virtual InstructionUse* getInstructionUseEnd() { return (&mInsnUse[0] + mX); }
virtual InstructionDefine* getInstructionDefineBegin() { return (mDefineResource); }
virtual InstructionDefine* getInstructionDefineEnd() { return (&mDefineResource[0] + mY); }
protected:
Uint8 mX;
Uint8 mY;
InstructionUse* mInsnUse;
InstructionDefine* mDefineResource;
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊInsnExternalUse/Define ¥
#endif
class InsnExternalUse : public InsnUseXDefineYFromPool
{
protected:
InstructionUse externalUse;
public:
InsnExternalUse(DataNode* inSrcPrimitive, Pool& inPool, Uint8 inUse) :
InsnUseXDefineYFromPool(inSrcPrimitive, inPool, inUse, 0) {}
virtual InstructionFlags getFlags() const { return (ifExternalInsn); }
#ifdef DEBUG_LOG
virtual void printPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("(external use)")); }
#endif
};
class InsnExternalDefine : public InsnUseXDefineYFromPool
{
protected:
InstructionDefine externalDef;
public:
InsnExternalDefine(DataNode* inSrcPrimitive, Pool& inPool, Uint8 inDefine) :
InsnUseXDefineYFromPool(inSrcPrimitive, inPool, 0, inDefine) {}
virtual InstructionFlags getFlags() const { return (ifExternalInsn); }
#ifdef DEBUG_LOG
virtual void printPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("(external def)")); }
#endif
};
#endif // INSTRUCTION_H

Просмотреть файл

@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// InstructionEmitter.cp
//
// Scott M. Silver
//
#include "InstructionEmitter.h"
#include "Primitives.h"
#include "Instruction.h"
#include "ControlNodes.h"
// define a temporary platform specific register
VirtualRegister& InstructionEmitter::
defineTemporary(Instruction& inDefineInsn, Uint8 inWhichOutput, VirtualRegisterKind constraint)
{
// newRegister stores inDefineInsn in the vr
VirtualRegister& vr = mVRAllocator.newVirtualRegister(constraint);
vr.setDefiningInstruction(inDefineInsn);
// make this instruction's output this register
inDefineInsn.addDefine(inWhichOutput, vr, constraint);
return vr;
}
// reuse register, basically update who defines this register
// and note that the passed in instruction redefines it
VirtualRegister& InstructionEmitter::
redefineTemporary(Instruction& inDefineInsn, VirtualRegister& inReuseRegister, Uint8 inWhichOutput, VirtualRegisterKind constraint)
{
inReuseRegister.setDefiningInstruction(inDefineInsn);
inDefineInsn.addDefine(inWhichOutput, inReuseRegister, constraint);
return (inReuseRegister);
}
InstructionDefine& InstructionEmitter::
defineTemporaryOrder(Instruction& inDefineInsn, Uint8 inWhichOutput)
{
InstructionDefine& newOrder = *new(mPool) InstructionDefine();
newOrder.name.instruction = &inDefineInsn;
inDefineInsn.addDefine(inWhichOutput, newOrder);
return (newOrder);
}
InstructionDefine& InstructionEmitter::
redefineTemporaryOrder(Instruction& inDefineInsn, InstructionDefine& inReuseOrder, Uint8 inWhichOutput)
{
inReuseOrder.name.instruction = &inDefineInsn;
inDefineInsn.addDefine(inWhichOutput, inReuseOrder);
return (inReuseOrder);
}
void InstructionEmitter::
useTemporaryOrder(Instruction& inDefineInsn, InstructionDefine& inOrder, Uint8 inWhichInput)
{
inDefineInsn.addUse(inWhichInput, inOrder);
}
// inID is used to indicate which of the two assigned registers to a producer
// you wish to use, eg for 32 bit types, etc
VirtualRegister* InstructionEmitter::
defineProducer(DataNode& inProducer, Instruction& inDefineInsn, Uint8 inWhichOutput, VirtualRegisterKind constraint, VirtualRegisterID inID)
{
return defineProducerInternal(inProducer, &inDefineInsn, inWhichOutput, NULL, constraint, inID);
}
void InstructionEmitter::
defineProducerWithExistingVirtualRegister(VirtualRegister& inVr, DataNode& inProducer, Instruction& inDefineInsn, Uint8 inWhichOutput, VirtualRegisterKind constraint)
{
defineProducerInternal(inProducer, &inDefineInsn, inWhichOutput, &inVr, constraint, vidLow);
}
inline VirtualRegister*
getVirtualRegisterAnnotationByID(DataNode& inDataNode, VirtualRegisterID inID)
{
if (inID == vidLow)
return (inDataNode.getLowVirtualRegisterAnnotation());
else if (inID == vidHigh)
return (inDataNode.getHighVirtualRegisterAnnotation());
else
{
assert(false);
return (NULL);
}
}
// inDefineInsn default to NULL
// inWhichOutput default to 0xFF
VirtualRegister* InstructionEmitter::
defineProducerInternal(DataNode& inProducer, Instruction* inDefineInsn, Uint8 inWhichOutput, VirtualRegister* inVr, VirtualRegisterKind constraint, VirtualRegisterID inID)
{
bool reallyDefiningProducer;
reallyDefiningProducer = (inDefineInsn != NULL);
switch (inProducer.getKind())
{
default:
assert(false);
break;
case vkCond:
// fix-me should we set the fact that this instruction
// touches a condition code here?
if (reallyDefiningProducer)
{
inProducer.annotate(*inDefineInsn);
inDefineInsn->addDefine(inWhichOutput, inProducer);
return (NULL);
}
break;
case vkMemory:
if (reallyDefiningProducer)
{
inProducer.annotate(*inDefineInsn);
inDefineInsn->addDefine(inWhichOutput, inProducer);
return (NULL);
}
break;
case vkDouble:
case vkInt:
case vkFloat:
case vkAddr:
assert(inID == vidLow);
case vkLong:
{
VirtualRegister* vr;
// check to see if a VR was assigned to inProducer
if (getVirtualRegisterAnnotationByID(inProducer, inID) == NULL)
{
// allocate a new VR
if (inVr == NULL)
vr = &mVRAllocator.newVirtualRegister(constraint);
else
vr = inVr;
vr->setDefiningInstruction(*inDefineInsn);
// attach to inProducer
if (inID == vidLow)
inProducer.annotateLow(*vr, constraint);
else if (inID == vidHigh)
inProducer.annotateHigh(*vr, constraint);
else
assert(false);
}
else
{
// there is already a VR attached to this producer
// make sure user did not try to specify a VR, this is
// programmer error
assert(inVr == NULL);
vr = getVirtualRegisterAnnotationByID(inProducer, inID);
vr->setDefiningInstruction(*inDefineInsn);
}
if (reallyDefiningProducer)
{
inDefineInsn->addDefine(inWhichOutput, *vr, constraint);
vr->setClass(constraint);
}
return (vr);
}
break;
}
// NEVER REACHED
return (NULL);
}
VirtualRegister* InstructionEmitter::
useProducer(DataNode& inProducer, Instruction& inUseInstruction, Uint8 inWhichInput, VirtualRegisterKind constraint, VirtualRegisterID inID)
{
// find out if there is a register assigned to this {producer, id}
// fix-me check cast
switch (inProducer.getKind())
{
default:
assert(false);
break;
case vkCond:
inUseInstruction.addUse(inWhichInput, inProducer);
break;
case vkMemory:
// now mark our dependence on VR
inUseInstruction.addUse(inWhichInput, inProducer);
break;
case vkDouble:
case vkInt:
case vkFloat:
case vkLong:
case vkAddr:
VirtualRegister* vr;
// make sure there is a register assigned to this already
// if not assign a new one with a NULL defining instruction
if (getVirtualRegisterAnnotationByID(inProducer, inID) == NULL)
vr = defineProducerInternal(inProducer, NULL, 0, NULL, constraint, inID); // define NULL instruction for this producer
else
vr = getVirtualRegisterAnnotationByID(inProducer, inID);
// now mark our dependence on VR
inUseInstruction.addUse(inWhichInput, *vr, constraint);
return vr;
}
return NULL;
}
void InstructionEmitter::
useTemporaryVR(Instruction& inInstruction, VirtualRegister& inVR, Uint8 inWhichInput, VirtualRegisterKind constraint)
{
inInstruction.addUse(inWhichInput, inVR, constraint);
}
Instruction& InstructionEmitter::
pushAbsoluteBranch(ControlNode& inSrc, ControlNode& inTarget)
{
InstructionList& instructions = inSrc.getInstructions();
Instruction& branchInsn = emitAbsoluteBranch(*(instructions.get(instructions.end())).getPrimitive(), inTarget);
instructions.addLast(branchInsn);
return (branchInsn);
}

Просмотреть файл

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
InstructionEmitter.h
Scott M. Silver
*/
#ifndef _H_INSTRUCTIONEMITTER_
#define _H_INSTRUCTIONEMITTER_
#include "Instruction.h"
#include "VirtualRegister.h"
#include "Primitives.h"
#include "Value.h"
class Pool;
struct InstructionDefine;
typedef uint16 NamedRule;
enum VirtualRegisterID { vidLow, vidHigh };
class InstructionEmitter
{
public:
InstructionEmitter(Pool& inPool, VirtualRegisterManager& vrMan) :
mPool(inPool),
mVRAllocator(vrMan) { }
VirtualRegister& defineTemporary(Instruction& inDefineInsn, Uint8 inWhichOutput, VirtualRegisterKind constraint = IntegerRegister);
VirtualRegister& redefineTemporary(Instruction& inDefineInsn, VirtualRegister& inReuseRegister, Uint8 inWhichOutput, VirtualRegisterKind constraint = IntegerRegister);
void useTemporaryVR(Instruction& inInstruction, VirtualRegister& inVR, uint8 inWhichInput, VirtualRegisterKind constraint = IntegerRegister);
InstructionDefine& defineTemporaryOrder(Instruction& inDefineInsn, Uint8 inWhichOutput);
InstructionDefine& redefineTemporaryOrder(Instruction& inDefineInsn, InstructionDefine& inReuseOrder, Uint8 inWhichOutput);
void useTemporaryOrder(Instruction& inDefineInsn, InstructionDefine& inOrder, Uint8 inWhichInput);
VirtualRegister* defineProducer(DataNode& inProducer, Instruction& inDefineInsn, Uint8 inWhichOutput, VirtualRegisterKind constraint = IntegerRegister, VirtualRegisterID inID = vidLow);
void defineProducerWithExistingVirtualRegister(VirtualRegister& inVr, DataNode& inProducer, Instruction& inDefineInsn, Uint8 inWhichOutput, VirtualRegisterKind constraint = IntegerRegister);
VirtualRegister* useProducer(DataNode& inProducer, Instruction& inUseInstruction, Uint8 inWhichInput, VirtualRegisterKind constraint = IntegerRegister, VirtualRegisterID inID = vidLow);
Instruction& pushAbsoluteBranch(ControlNode& inSrc, ControlNode& inTarget);
private:
VirtualRegister* defineProducerInternal(DataNode& inProducer, Instruction* inDefineInsn = NULL, uint8 inWhichOutput = 0, VirtualRegister* inVr = NULL, VirtualRegisterKind constraint = IntegerRegister, VirtualRegisterID inID = vidLow);
virtual Instruction& emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget) = 0;
protected:
Pool& mPool;
public:
VirtualRegisterManager& mVRAllocator;
};
#endif // _H_INSTRUCTIONEMITTER_

Просмотреть файл

@ -0,0 +1,86 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ../..
DIRS = md
SUBMODULES = $(DIRS)
CPPSRCS = Backend.cpp \
CGScheduler.cpp \
CodeGenerator.cpp \
IGVisualizer.cpp \
Instruction.cpp \
InstructionEmitter.cpp \
NativeCodeCache.cpp \
NativeFormatter.cpp \
HTMLMethodDump.cpp \
Scheduler.cpp \
ExceptionTable.cpp \
$(NULL)
LOCAL_EXPORTS = Backend.h \
Burg.h \
CGScheduler.h \
CodeGenerator.h \
ControlNodeScheduler.h \
ExceptionTable.h \
FormatStructures.h \
HTMLMethodDump.h \
IGVisualizer.h \
Instruction.h \
InstructionEmitter.h \
NativeCodeCache.h \
NativeFormatter.h \
Scheduler.h \
$(NULL)
MODULE_NAME = EF
#######################################################################
# (2) Include "component" configuration information. #
#######################################################################
include $(DEPTH)/config/config.mk
#######################################################################
# (3) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#######################################################################
# (4) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
# Special rules for Instruction.cpp for gcc
ifneq ($(OS_ARCH),WINNT)
$(OBJDIR)/Instruction$(OBJ_SUFFIX): Instruction.cpp
$(CCC) -c $(filter-out $(EXC_FLAGS),$(CFLAGS)) $< -o $@
endif

Просмотреть файл

@ -0,0 +1,371 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// NativeCodeCache
//
// Scott M. Silver
//
#include "NativeCodeCache.h"
#include "StringUtils.h"
#include "ClassWorld.h"
#include "FieldOrMethod.h"
#include "NativeMethodDispatcher.h"
#include "JavaVM.h"
UT_DEFINE_LOG_MODULE(NativeCodeCache);
#ifdef _WIN32
Uint8* CacheEntry::asynchVersion(Pool& pool, Uint8*& ip)
{
Uint8* src = start.getFunctionAddress();
Int32 sz = end-src;
Uint8* dest = new(pool) Uint8[sz];
Uint32* asynchPoints = eTable->getAsynchPoints();
int numberofAPoints = eTable->getNrOfAsynchPoints();
// loop through code and for each byte corresponding to an asynchronous
// checkpoint, insert 'int 3' (0xCC).
memcpy((void*)dest,(const void*)src,sz);
for (int j=0; j<numberofAPoints; j++)
dest[asynchPoints[j]] = 0xcc;
ip = dest + (ip-src);
return dest;
}
#else
Uint8* CacheEntry::asynchVersion(Pool& /*pool*/, Uint8*& /*ip*/)
{
assert(false);
return NULL;
}
#endif
// there is one of these per VM instantiation
NativeCodeCache NativeCodeCache::sNativeCodeCache;
// Access to the database of classes
extern ClassWorld world;
#ifdef DEBUG_LOG
static void printFrame(Method *method);
#endif
// acquireMemory
//
// Reserve inBytes of data for (potentially) a new method, or data
Uint8* NativeCodeCache::
acquireMemory(const size_t inBytes)
{
// is Pool new thread safe?
return ((Uint8*) new(mPool) char[inBytes]);
}
// mapMemoryToMethod
//
// Assign a "name" to a method. When other users ask the cache
// for a given method, this is the entry point returned. The
// first call for a specific MethodDescriptor M and function f,
// will assign f to M.
//
// FIX-ME do all HashTable entrypoints need monitors?
void NativeCodeCache::
mapMemoryToMethod( const MethodDescriptor& inMethodDescriptor,
PlatformTVector inWhere,
Uint8* inEnd,
ExceptionTable* pExceptionTable,
StackFrameInfo& inPolicy)
{
CacheEntry* existingEntry = NULL;
TemporaryStringCopy key(inMethodDescriptor.method->toString());
mIndexByDescriptor.get(key, &existingEntry);
if (!existingEntry)
{
CacheEntry& cacheEntry = *new(mPool) CacheEntry(inMethodDescriptor);
cacheEntry.start = inWhere;
cacheEntry.end = inEnd;
cacheEntry.eTable = pExceptionTable;
cacheEntry.policy = inPolicy;
mIndexByDescriptor.add(key, &cacheEntry);
mIndexByRange.append(&cacheEntry);
}
else
{
existingEntry->start = inWhere;
existingEntry->end = inEnd;
existingEntry->eTable = pExceptionTable;
existingEntry->policy = inPolicy;
}
}
// lookupByRange
//
// Purpose: used for stack crawling / debugging purposes
// In: pointer to memory
// Out: pointer to cache entry if in code cache (NULL otherwise)
//
// Notes: currently we do a linear search of a vector of methods, eventually
// we'll want a better search strategy
CacheEntry* NativeCodeCache::
lookupByRange(Uint8* inAddress)
{
for(CacheEntry** ce= mIndexByRange.begin(); ce < mIndexByRange.end(); ce++)
{
#ifdef GENERATE_FOR_X86
if ((*ce)->stub <= inAddress && (*ce)->stub + 10 > inAddress)
return *ce;
else
#endif
if(((*ce)->start.getFunctionAddress() <= inAddress) && (inAddress < (*ce)->end))
return *ce;
}
return NULL;
}
// lookupByDescriptor
//
// Looks up method inMethodDescriptor, if inMethodDescriptor
// is not in the cache, this generates a new "stub" function
// (which will compile inMethodDescriptor and backpatch the caller)
// Since we have two entries in the CacheEntry, one for stub and
// the other for function, we return the function if it exists
// otherwise we return the stub.
// inLookupOnly - do not create a stub if the lookup fails
addr NativeCodeCache::
lookupByDescriptor(const MethodDescriptor& inMethodDescriptor, bool /*inhibitBackpatch*/, bool inLookupOnly)
{
Method *method = inMethodDescriptor.method;
TemporaryStringCopy key(method->toString());
CacheEntry* cacheEntry = NULL;
mIndexByDescriptor.get(key, &cacheEntry);
// short circuit if inLookupOnly
if (inLookupOnly && !cacheEntry)
return (functionAddress(NULL));
if (!cacheEntry)
{
CacheEntry& newEntry = *new(mPool) CacheEntry(inMethodDescriptor);
newEntry.stub = (unsigned char*) generateCompileStub(*this, newEntry);
newEntry.start.setTVector(NULL);
newEntry.end = NULL;
newEntry.eTable = NULL;
// FIX set shouldBackPatch to always false. Note that this
// means that we compile evry function every time
newEntry.shouldBackPatch = false;
//newEntry.shouldBackPatch = !method->getDynamicallyDispatched();
cacheEntry = &newEntry;
mIndexByDescriptor.add(key, cacheEntry);
mIndexByRange.append(cacheEntry);
}
bool inhibitBackpatching = false;
inhibitBackpatching = VM::theVM.getInhibitBackpatching();
if (cacheEntry->start.getFunctionAddress() && !inhibitBackpatching)
return (functionAddress((void (*)())cacheEntry->start.getFunctionAddress()));
else
{
if (!cacheEntry->stub)
cacheEntry->stub = (unsigned char*) generateCompileStub(*this, *cacheEntry);
return (functionAddress((void (*)())cacheEntry->stub));
}
}
UT_DEFINE_LOG_MODULE(NativeCodeCacheMonitor);
// compileOrLoadMethod
//
// If the method pointed to by inCacheEntry is a native method, resolve and load
// the native code library. Otherwise compile the method's bytecode into
// native code. Either way, return a pointer to the resulting native code.
// Sets shouldBackPatch to true if it is neccessary to back-patch the method.
static void*
compileOrLoadMethod(const CacheEntry* inCacheEntry, bool &shouldBackPatch)
{
Method* method;
// if this function is already compiled then just return it
if (inCacheEntry->start.getFunctionAddress() != NULL)
{
shouldBackPatch = inCacheEntry->shouldBackPatch;
goto ExitReturnFunc;
}
else
{
NativeCodeCache::enter();
// maybe we slept while someone else was compiling, if so
// don't do any work.
if (inCacheEntry->start.getFunctionAddress() != NULL)
goto ExitReturnFunc;
method = inCacheEntry->descriptor.method;
// If this is a native method, then resolve it appropriately
if (method->getModifiers() & CR_METHOD_NATIVE)
{
addr a = NativeMethodDispatcher::resolve(*method);
if (!a)
{
NativeCodeCache::exit();
UT_LOG(NativeCodeCache, PR_LOG_ERROR, ("\tCould not resolve native method %s\n", method->getName()));
runtimeError(RuntimeError::linkError);
}
else
UT_LOG(NativeCodeCache, PR_LOG_DEBUG, ("\tResolved native method %s\n", method->getName()));
NativeCodeCache &cache = NativeCodeCache::getCache();
void* code = generateNativeStub(cache, *inCacheEntry, addressFunction(a));
PlatformTVector tVector;
tVector.setTVector((Uint8*)code);
int codeLength = 0; // We don't know the length of native methods yet
/*ExceptionTable* pExceptionTable = NULL; */ // FIX native methods don't have exception tables yet
StackFrameInfo policy; // FIX we don't know the stack layout policies yet, so pass in junk
cache.mapMemoryToMethod(inCacheEntry->descriptor, tVector, (Uint8*)code + codeLength, NULL, policy);
}
else
method->compile();
}
ExitReturnFunc:
NativeCodeCache::exit();
assert(inCacheEntry->start.getFunctionAddress());
shouldBackPatch = inCacheEntry->shouldBackPatch;
EventBroadcaster::broadcastEvent(gCompileOrLoadBroadcaster, kEndCompileOrLoad, inCacheEntry->descriptor.method);
return (inCacheEntry->start.getFunctionAddress());
/*
ExitMonitorThrowCompileException:
PR_CExitMonitor((void*)inCacheEntry);
assert(false);
return (NULL);
*/
}
// compileAndBackPatchMethod
//
// compile the method pointed to by inCacheEntry and then back patch
// the caller.
//
// inLastPC = address of next native instruction to be executed
// if the callee executed and returned. (where callee is the method that
// is to be compiled)
extern "C" void*
compileAndBackPatchMethod(const CacheEntry* inCacheEntry, void* inLastPC, void* inUserDefined)
{
bool shouldBackPatch;
void *nativeCode = compileOrLoadMethod(inCacheEntry, shouldBackPatch);
if (VM::theVM.getInhibitBackpatching())
shouldBackPatch = false;
#ifdef DEBUG
if (VM::theVM.getTraceAllMethods())
{
Method *method = inCacheEntry->descriptor.method;
printFrame(method);
}
#endif
/* Back-patch method only if method was resolved statically */
return (shouldBackPatch) ?
(backPatchMethod(nativeCode, inLastPC, inUserDefined)) : nativeCode;
}
#ifdef DEBUG_LOG
// C-entry point so we can call this from
// the MSVC debugger
void NS_EXTERN
printMethodTable()
{
NativeCodeCache::getCache().printMethodTable(UT_LOG_MODULE(NativeCodeCache));
}
// printMethodTable
//
// Print out all the methods currently in the cache, with their
// ExceptionTables
void NativeCodeCache::
printMethodTable(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n__________________Method Table___________________\n"));
for(CacheEntry** ce= mIndexByRange.begin(); ce < mIndexByRange.end(); ce++)
{
Uint8* pStart = (*ce)->start.getFunctionAddress();
Uint8* pEnd = (*ce)->end;
const char* pName= (*ce)->descriptor.method->toString();
ExceptionTable* eTable= (*ce)->eTable;
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("[%#010x-%#010x] %s\n", Uint32(pStart), Uint32(pEnd), pName));
if(eTable)
eTable->printShort(f);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n"));
}
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n\n"));
}
UT_EXTERN_LOG_MODULE(StackWalker);
#include "StackWalker.h"
// printFrame
//
// Print a frame of a given method (which is
// the caller). This can be called from a debugger
static void printFrame(Method *method)
{
UT_SET_LOG_LEVEL(StackWalker, PR_LOG_DEBUG);
Frame frame;
frame.moveToPrevFrame();
frame.moveToPrevFrame();
// Indent the frame according to stack depth
int stackDepth = Frame::getStackDepth();
int i;
// Discount the stack frames used for internal EF native code
stackDepth -= 7;
if (stackDepth < 0)
stackDepth = 0;
for (i = 0; i < stackDepth; i++)
UT_LOG(StackWalker, PR_LOG_ALWAYS, (" "));
Frame::printWithArgs(UT_LOG_MODULE(StackWalker), (Uint8*)(frame.getBase()), method);
UT_LOG(StackWalker, PR_LOG_ALWAYS, ("\n"));
}
#endif // DEBUG_LOG

Просмотреть файл

@ -0,0 +1,177 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
NativeCodeCache
*/
#ifndef _NATIVE_CODE_CACHE_
#define _NATIVE_CODE_CACHE_
#include "ExceptionTable.h"
#include "FormatStructures.h"
#include "Pool.h"
#include "Attributes.h"
#include "InfoItem.h"
#include "HashTable.h"
#include "FieldOrMethod.h"
#include "LogModule.h"
#include "prmon.h"
//-----------------------------------------------------------------------------------------------------------
// This is the key for entries in the cache
// Currently it retainst he "fully qualified" name
// of the method.
struct MethodDescriptor
{
MethodDescriptor(Method& inMethod) :
method(&inMethod) { };
Method *method; // interned full name string describing this method
void operator=(const MethodDescriptor& inCopy) { method = inCopy.method; }
};
//-----------------------------------------------------------------------------------------------------------
struct PlatformTVector
{
Uint8* mTVector;
void
setTVector(Uint8* inTVector) { mTVector = inTVector; }
Uint8*
getFunctionAddress() const
{
#ifdef GENERATING_FOR_POWERPC
if (mTVEctor != NULL)
return (*(Uint8***)mTVector);
else
return (NULL);
#elif defined(GENERATING_FOR_X86)
return (mTVector);
#else
return (mTVector); // FIX-ME This probably is not right
#endif
}
Uint8*
getEnvironment() const
{
#ifdef GENERATING_FOR_POWERPC
return (*((Uint8***)mTVector + 1));
#else
assert(false);
return (NULL);
#endif
}
};
//-----------------------------------------------------------------------------------------------------------
// An entry in the CodeCache
// Not intended for use outside of NativeCode Cache
struct CacheEntry
{
CacheEntry(const MethodDescriptor& inMethodDescriptor) :
descriptor(inMethodDescriptor), stub(0) { }
MethodDescriptor descriptor; // unique descriptor of the method
PlatformTVector start; // default entry into the function
Uint8* end; // pointer to byte _after_ end of function
Uint8* stub; // if non-NULL this is the address of the stub function
ExceptionTable* eTable; // pointer to the exception table
mutable bool shouldBackPatch; // If true, specifies that the call site must be backpatched on compile
// FIX for now the restore policy will be kept in the NativeCodeCache, later we may want to store the restore policies elsewhere
StackFrameInfo policy; // specifies how to restore registers as stack frames are popped
Uint8* asynchVersion(Pool& pool, Uint8*& ip);
};
//-----------------------------------------------------------------------------------------------------------
class NativeCodeCache
{
PRMonitor* _mon;
public:
NativeCodeCache() :
mIndexByDescriptor(mPool),
mIndexByRange()
{ _mon = PR_NewMonitor(); }
Uint8* acquireMemory(const size_t inBytes);
void mapMemoryToMethod( const MethodDescriptor& inMethodDescriptor,
PlatformTVector inWhere,
Uint8* inEnd,
ExceptionTable* pExceptionTable,
StackFrameInfo& inPolicy );
addr lookupByDescriptor(const MethodDescriptor& inDescriptor, bool inhibitBackpatch, bool inLookupOnly = false);
CacheEntry* lookupByRange(Uint8* inAddress);
protected:
HashTable<CacheEntry*> mIndexByDescriptor; // hashtable of entrypoints to methods
Vector<CacheEntry*> mIndexByRange; // maps range -> method
public:
Pool mPool; // resource for our cache
static inline NativeCodeCache& getCache() { return (NativeCodeCache::sNativeCodeCache); }
static NativeCodeCache sNativeCodeCache;
#ifdef DEBUG
void printMethodTable(LogModuleObject &f);
#endif
static void enter() {
PR_EnterMonitor(sNativeCodeCache._mon);
}
static void exit() {
PR_ExitMonitor(sNativeCodeCache._mon);
}
};
// inCacheEntry: reference to actual CacheEntry in memory
// inCache: the cache in question
// creates a bit of code which when called compiles the method
// described by inCacheEntry.descriptor and then calls "compileAndBackPatchMethod"
// then jump to the method returned by compileAndBackPatchMethod
extern void*
generateCompileStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry);
extern void*
generateNativeStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry, void *nativeFunction);
extern void *
generateJNIGlue(NativeCodeCache& inCache,
const CacheEntry& inCacheEntry,
void *nativeFunction);
extern "C" void *
compileAndBackPatchMethod(const CacheEntry* inCacheEntry, void* inLastPC, void* inUserDefined);
// atomically backpatch a caller of a stub generated with generateCompileStub
// inMethodAddress the address of the callee
// inLastPC the next PC to be executed up return from the callee
// inUserDefined is a (probably) per platform piece of data that will be passed
// on to the backPatchMethod function.
void* backPatchMethod(void* inMethodAddress, void* inLastPC, void* inUserDefined);
void NS_EXTERN printMethodTable();
#endif // _NATIVE_CODE_CACHE_

Просмотреть файл

@ -0,0 +1,374 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// NativeFormatter.cpp
//
// Scott M. Silver
//
// Actually output native code for a function to memory (from the NativeCodeCache).
//
// Summary
//
// A NativeFormatter takes an InstructionEmitter (a per/method data structure) and a Method
// (a runtime representation of a method) and actually outputs the native representation
// of the function out to memory. Memory is acquired from the NativeCodeCache.
//
// Each function has the following structural layout:
//
// ControlNodes Formatted Correlation
// PreMethod
// ckBegin Prolog
// ckReturn Epilog
// ckEnd PostMethod
//
// Prolog and Epilog are normal entry and exit points from a function. Note that even
// if a function does not return a value a ckReturn node must exist.
// PreMethod and PostMethod are invented pieces of code/data which may be used
// for debuggers or stack inspection (eg. MacsBug symbols, TraceBack tables, etc...)
#include "NativeFormatter.h"
#include "ControlGraph.h"
#include "InstructionEmitter.h"
#include "NativeCodeCache.h"
#include "ExceptionTable.h"
#ifdef DEBUG
#include "JavaVM.h" // to insert breakpoints in jitted code
#endif
UT_DEFINE_LOG_MODULE(ExceptionMatrix);
//-----------------------------------------------------------------------------------------------------------
// format
//
// Actually output the native instructions of a method out to memory
// acquired from the cache.
//
// outInfo: Normally temporal information about the formatting the function
// mainly used for debugging purposes
void* NativeFormatter::
format(Method& inMethod, FormattedCodeInfo* outInfo)
{
// now setup a FormattedCodeInfo with collected data about the method
FormattedCodeInfo fci;
fci.method = &inMethod;
// Need policy before any formatting can be done
mFormatter.initStackFrameInfo();
mFormatter.calculatePrologEpilog(inMethod, fci.prologSize, fci.epilogSize);
mFormatter.calculatePrePostMethod(inMethod, fci.preMethodSize, fci.postMethodSize);
// potentially shortens or lengthens branches
fci.bodySize = resolveBranches(fci.prologSize, fci.epilogSize);
// actually grab some memory for this method
Uint32 methodSize = fci.preMethodSize + fci.bodySize + fci.postMethodSize;
#ifdef DEBUG
#if defined(XP_PC) || defined(LINUX)
DebugDesc *bps;
Uint32 nbps;
nbps = VM::theVM.getExecBreakPoints(bps);
bool hasInt3 = false;
bool foundBreakPoint = false;
for (Uint32 index = 0; index < nbps; index++)
if (inMethod.isSelf(bps[index].className, bps[index].methodName, bps[index].sig)) {
methodSize++; // for int 3
fci.methodStart = NativeCodeCache::getCache().acquireMemory(methodSize);
*fci.methodStart++ = 0xcc;
hasInt3 = true;
foundBreakPoint = true;
break;
}
if (!foundBreakPoint)
fci.methodStart = NativeCodeCache::getCache().acquireMemory(methodSize);
#else
fci.methodStart = NativeCodeCache::getCache().acquireMemory(methodSize);
#endif
#else
fci.methodStart = NativeCodeCache::getCache().acquireMemory(methodSize);
#endif
// build the exception table
// FIX FIX FIX
// for now just grab some memory
Pool* tempPool = new Pool();
ExceptionTable& eTable = buildExceptionTable(fci.methodStart, tempPool);
DEBUG_LOG_ONLY(eTable.print(UT_LOG_MODULE(ExceptionMatrix)));
DEBUG_LOG_ONLY(eTable.printFormatted(UT_LOG_MODULE(ExceptionMatrix), nodes, nNodes, false));
// fci is now valid
mFormatter.beginFormatting(fci);
// dump out the function to memory
outputNativeToMemory(fci.methodStart, fci);
// make an entry point for this function
MethodDescriptor md(inMethod);
mFormatter.endFormatting(fci);
#if defined(DEBUG) && (defined(XP_PC) || defined(LINUX))
if (hasInt3)
fci.methodStart--;
#endif
PlatformTVector functionDescriptor;
functionDescriptor.setTVector(mFormatter.createTransitionVector(fci));
fci.methodEnd = fci.methodStart + methodSize;
#ifdef WIN32
// temporarily check this invariant
assert((fci.methodStart + methodSize) == (functionDescriptor.getFunctionAddress() + methodSize));
#endif
// Eventually we may wish to have choose different GPR/FPR save procedures and local store sizes for
// different nodes in the control graph. Correspondingly the restore policies in an exception unwind
// can vary by control node -- ie they are not necessarily the same across the whole method.
// For now we will give each method the same info, but we reserve the right later to make this optimisation.
// FIX for mow, NativeCodeCache::mapMemoryToMethod caches a copy of the policy
StackFrameInfo& policy = mFormatter.getStackFrameInfo();
NativeCodeCache::getCache().mapMemoryToMethod(md, functionDescriptor, fci.methodEnd, &eTable, policy);
if (outInfo)
*outInfo = fci;
#ifdef DEBUG_LOG
// debugging stuff
if(VM::theVM.getEmitHTML())
dumpMethodToHTML(fci, eTable);
#endif
// return the entry point
return (fci.methodStart);
}
// outputNativeToMemory
// actually ouput this method to memory starting at inWhere.
// inInfo contains some precalculated information about the method
// which is useful in its formatting.
void NativeFormatter::
outputNativeToMemory(void* inWhere, const FormattedCodeInfo& inInfo)
{
Uint32 curOffset;
char* nextMemory = (char*) inWhere;
assert(nodes[0]->hasControlKind(ckBegin));
assert(nodes[nNodes-1]->hasControlKind(ckEnd));
// first output the PreMethod
mFormatter.formatPreMethodToMemory(nextMemory, inInfo);
nextMemory += inInfo.preMethodSize;
mFormatter.formatPrologToMemory(nextMemory);
nextMemory += inInfo.prologSize;
curOffset = inInfo.prologSize;
for (Uint32 n = 0; n < nNodes; n++)
{
InstructionList& instructions = nodes[n]->getInstructions();
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i))
{
Instruction& curInstruction = instructions.get(i);
curInstruction.formatToMemory(nextMemory, curOffset, mFormatter);
curOffset += curInstruction.getFormattedSize(mFormatter);
nextMemory += curInstruction.getFormattedSize(mFormatter);
}
if (nodes[n]->hasControlKind(ckReturn))
{ mFormatter.formatEpilogToMemory(nextMemory);
curOffset += inInfo.epilogSize;
nextMemory += inInfo.epilogSize;
}
}
// Now end with the PostMethod
mFormatter.formatPostMethodToMemory(nextMemory, inInfo);
//nextMemory += inInfo.preMethodSize;
}
// accumulateSize
//
// Accumulate the size of the the formatted (ie in-memory) representation
// of each Instruction in this ControlNode. ckBegin and ckReturn nodes
// include the prolog and epilog size, respectively.
Uint32 NativeFormatter::
accumulateSize(ControlNode& inNode, Uint32 inPrologSize, Uint32 inEpilogSize)
{
Uint32 accum;
InstructionList& instructions = inNode.getInstructions();
accum = 0;
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i))
accum += instructions.get(i).getFormattedSize(mFormatter);
if (inNode.hasControlKind(ckReturn))
accum += inEpilogSize;
else if (inNode.hasControlKind(ckBegin))
accum += inPrologSize;
return (accum);
}
// resolveBranches
//
// for each node in the scheduled ControlNodes
// assign a native offset to each ControlNode.
// decisions to make short/long branches would normally be made
// here. returns the size of the formatted method. including
// epilog and prolog. The PreMethod and PostMethod are not
// considered here.
Uint32 NativeFormatter::
resolveBranches(Uint32 inPrologSize, Uint32 inEpilogSize)
{
Uint32 accumSize;
accumSize = 0;
for (Uint32 i = 0; i < nNodes; i++)
{
ControlNode& node = *nodes[i];
Uint32 formattedSize;
node.setNativeOffset(accumSize);
// fix-me this should be a function of the list, ie the list
// should maintain the size of the instructions in it
formattedSize = accumulateSize(node, inPrologSize, inEpilogSize);
accumSize += formattedSize;
}
// make long/short branch decisions here
return (accumSize);
}
// buildExceptionTable
// In: start of method
// pool to create table in
// Out: the Exception Table
// #define DEBUG_GENERATE_EXCEPTION_MATRIX
// Debugging code to print out a matrix of exception handlers
// Ugly -- farm out to a class, time permitting
#ifdef DEBUG_GENERATE_EXCEPTION_MATRIX
#define DEBUG_SET_UP_EXCEPTION_MATRIX \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("\n\nBuilding Exception Table\n")); \
assert(nNodes < 100); /* dumb check */ \
int _exceptionMatrix[100][100]; \
Uint32 _rows, _cols; \
for(_rows = 0; _rows < nNodes; _rows++) \
for(_cols = 0; _cols < nNodes; _cols++) \
_exceptionMatrix[_rows][_cols] = 0; \
Uint32 _addorder = 1;
#define DEBUG_ADD_ENTRY_TO_EXCEPTION_MATRIX \
_exceptionMatrix[node->dfsNum][e->getTarget().dfsNum] = _addorder++;
#define DEBUG_PRINT_EXCEPTION_MATRIX \
/* print header */ \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("\n\nException Matrix\n ")); \
for(_cols = 0; _cols < nNodes; _cols++) \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("N%02d ", nodes[_cols]->dfsNum)); \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("\n")); \
/* print rows */ \
for(_rows = 0; _rows < nNodes; _rows++) \
{ \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, (" N%02d: ", nodes[_rows]->dfsNum)); \
for(_cols = 0; _cols < nNodes; _cols++) \
{ \
_addorder = _exceptionMatrix[nodes[_rows]->dfsNum][nodes[_cols]->dfsNum]; \
if(_addorder != 0) \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, (" %02d ", _addorder)); \
else \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, (" - ")); \
} \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("\n")); \
} \
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("\n\n\n"));
#else
#define DEBUG_SET_UP_EXCEPTION_MATRIX
#define DEBUG_ADD_ENTRY_TO_EXCEPTION_MATRIX
#define DEBUG_PRINT_EXCEPTION_MATRIX
#endif // DEBUG_GENERATE_EXCEPTION_MATRIX
ExceptionTable& NativeFormatter::
buildExceptionTable(Uint8* methodStart, Pool* inPool)
{
Uint32 i;
DEBUG_SET_UP_EXCEPTION_MATRIX;
ExceptionTableBuilder eBuilder(methodStart);
for (i = 0; i < nNodes; i++) // iterate through nodes in scheduled order
{
ControlNode* node = nodes[i];
ControlKind kind = node->getControlKind();
if(kind == ckExc || kind == ckAExc || kind == ckThrow)
{ // has exception
ControlNode::ExceptionExtra& excExtra = node->getExceptionExtra();
const Class **exceptionClass = excExtra.handlerFilters + excExtra.nHandlers;
if (kind == ckAExc)
eBuilder.addAEntry(node->getNativeOffset());
// iterate through exception edges
Uint32 startIndex = 0; // start extending exceptions from beginning of table
ControlEdge *e = node->getSuccessorsEnd();
for (Uint32 exceptNum = 0; exceptNum < excExtra.nHandlers; exceptNum++)
{
e--; // move to previous handler edge
exceptionClass--; // move to previous handler filter
assert(&(e->getSource()) == node);
if(e->getTarget().getControlKind() != ckEnd) // only interested in exceptions handled locally
{
// assert(e->getTarget().getControlKind() == ckCatch); // targets of exception edges must be End or Catch nodes
ExceptionTableEntry ete; // container for exception info passing
ete.pStart = node->getNativeOffset();
ete.pEnd = nodes[i+1]->getNativeOffset(); // points to byte after 'node'
ete.pHandler = e->getTarget().getNativeOffset();
ete.pExceptionType = *exceptionClass;
UT_LOG(ExceptionMatrix, PR_LOG_ALWAYS, ("N%02d->N%02d ", node->dfsNum, e->getTarget().dfsNum));
eBuilder.addEntry(startIndex, ete); // note that startIndex is passed by reference
DEBUG_ADD_ENTRY_TO_EXCEPTION_MATRIX;
}
}
}
}
DEBUG_PRINT_EXCEPTION_MATRIX;
DEBUG_ONLY(eBuilder.checkInOrder());
// copy table into new (efficient) storage and insert into NativeCodeCache
ExceptionTable* eTable = new(*inPool) ExceptionTable(eBuilder, *inPool);
return (*eTable);
}

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: NativeFormatter.h
// Author: smsilver
//
#ifndef H_NATIVEFORMATTER
#define H_NATIVEFORMATTER
class ControlNode;
class Instruction;
class Pool;
class ExceptionTable;
struct MethodDescriptor;
#include "FormatStructures.h"
#include "LogModule.h"
#define INCLUDE_EMITTER
#include "CpuInfo.h"
#undef INCLUDE_EMITTER
class NativeFormatter
{
protected:
MdEmitter& mEmitter;
MdFormatter mFormatter;
ControlNode** nodes;
Uint32 nNodes;
void outputNativeToMemory(void* inWhere, const FormattedCodeInfo& inInfo);
Uint32 accumulateSize(ControlNode& inNode, Uint32 inPrologSize, Uint32 inEpilogSize);
Uint32 resolveBranches(Uint32 inPrologSize, Uint32 inEpilogSize);
ExceptionTable& buildExceptionTable(Uint8* methodMemoryStart, Pool* inPool);
public:
NativeFormatter(MdEmitter& inEmitter, ControlNode** mNodes, uint32 mNNodes) :
mEmitter(inEmitter), mFormatter(mEmitter), nodes(mNodes), nNodes(mNNodes) {}
void* format(Method& inMethod, FormattedCodeInfo* outInfo = NULL);
#ifdef DEBUG_LOG
void dumpMethodToHTML(FormattedCodeInfo& fci, ExceptionTable& inExceptionTable); // see HTMLMethodDump.cpp for implementation
#endif
};
#endif // H_NATIVEFORMATTER

Просмотреть файл

@ -0,0 +1,374 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// LinearInstructionScheduler.cpp
//
// Peter DeSantis 28 April 1997
#include "Scheduler.h"
#include "Vector.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "DoublyLinkedList.h"
#include "Instruction.h"
void swapRootToEnd(Vector<RootPair>& inRoots, RootPair* inSwapToEnd);
// schedule [no real purpose currently] FIX-ME
// Calls the appropriate internal routine(s).
void LinearInstructionScheduler::
schedule(Vector<RootPair>& roots, ControlNode& controlNode)
{
linearSchedule(roots, controlNode);
}
// The primary goal of linear scheduling is to schedule all the instructions
// which are derived from one line of src code one after another. There are numerous
// ways to meet this objective. The simpliest method is to do a simple prioritived
// topological sort of the control node. The priority is that from any node the
// algorith follows the edges in increasing linenumber order. (Each instruction has
// a line number associated with it which corresponds to src code line number.) As the
// topological sort backtracks it inserts the instruction which it is leaving into
// the list of instructions in the control node. The instructions have to be inserted
// in an ordered fashion such that each new instruction is added at the end of the
// section with the same associated line numbers. Currently this is done in the
// simpliest n^2 fashion. If scheduling is determined to take significant time this
// running time can be improved by using a binary search insertion routine.
/*
priorityTopoEmit
does a priority topological sort of the instructions rooted at root and fills the
controlnode's list ordered list of instructions.
*/
void LinearInstructionScheduler::
priorityTopoEmit(Instruction* inInstruction, ControlNode& controlNode)
{
if (controlNode.haveScheduledInstruction(*inInstruction))
return;
InstructionUse* conditionCodeUse = NULL;
InstructionUse* curUse;
Instruction* curInstruction;
for (curUse = inInstruction->getInstructionUseBegin();
curUse < inInstruction->getInstructionUseEnd();
curUse++)
{
if(curUse->kind == udCond)
{
assert(conditionCodeUse == NULL); // Instructions only allowed to use one condition code
conditionCodeUse = curUse;
} else {
curInstruction = CodeGenerator::instructionUseToInstruction(*curUse);
// Only need to schedule if it hasn't been scheduled and it is in coltrolNode
if (curInstruction != NULL
&& curInstruction->getPrimitive()->getContainer() == inInstruction->getPrimitive()->getContainer())
{
priorityTopoEmit(curInstruction, controlNode);
}
}
}
if(conditionCodeUse != NULL)
{
curInstruction = CodeGenerator::instructionUseToInstruction(*conditionCodeUse);
if (curInstruction != NULL
&& curInstruction->getPrimitive()->getContainer() == inInstruction->getPrimitive()->getContainer())
{
priorityTopoEmit(curInstruction, controlNode);
}
}
// Now insert the instruction into the controlnodes list of instructions
controlNode.addScheduledInstruction(*inInstruction);
}
// swapRootToEnd
//
// Swaps the passed in root to the end of the root vector
void
swapRootToEnd(Vector<RootPair>& inRoots, RootPair* inSwapToEnd)
{
RootPair oldRoot;
RootPair* end = inRoots.end() - 1;
oldRoot = *end;
*end = *inSwapToEnd;
*inSwapToEnd = oldRoot;
}
/*
linearSchedule
Does a prioritized linear search which fills in controlNode->instructions from the
back to the front.
*/
void LinearInstructionScheduler::
linearSchedule(Vector<RootPair>& roots, ControlNode& controlNode)
{
// FIX-ME move this stuff to the function that builds up roots
if (controlNode.hasControlKind(ckReturn))
{
// Enforce the register allocator requirement that code emitted for
// Result nodes be placed at the end of the block
// The register allocator has no "global scope" uses, so basically it
// would be sufficient to place the ExternalUse instruction emitted for
// each Result node at the end, however we just go ahead and make sure
// all of the code for a Result is last thing scheduled in a node.
// Hopefully the register allocator will have globally scoped uses
// in the future. FIX-ME.
RootPair* curRoot;
RootPair* resultRoot = NULL;
// find poResult
for (curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
if (curRoot->root->hasCategory(pcResult))
{
assert(!resultRoot); // verify there is only one Result node (is this true?)
resultRoot = curRoot;
#ifndef DEBUG
break;
#endif
}
// it is not necessary that there be a pcResult
if (resultRoot)
swapRootToEnd(roots, resultRoot);
}
else if (controlNode.hasControlKind(ckExc))
{
// Satisfy constraint that an exception producing primitive
// must be the last excecuted in the ControlNode
RootPair* curRoot;
RootPair* exceptionRoot = NULL;
// find poResult
for (curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
if (curRoot->root->canRaiseException())
{
assert(!exceptionRoot); // verify there is only one exception generating root
exceptionRoot = curRoot;
#ifndef DEBUG
break;
#endif
}
assert(exceptionRoot);
swapRootToEnd(roots, exceptionRoot);
}
renumberCN(roots, controlNode);
RootPair* curRoot;
Primitive* anchoredPrimitive;
// take care of any anchored primitives last, so find out the anchored primitive
if (controlNode.hasControlKind(ckIf) || controlNode.hasControlKind(ckSwitch))
anchoredPrimitive = &controlNode.getControlPrimExtra();
else
anchoredPrimitive = NULL;
//For each primary root, rum topologicalEmit
for(curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
{
if(curRoot->isPrimary && (curRoot->root != anchoredPrimitive))
{
if (curRoot->root->getInstructionRoot() != NULL)
priorityTopoEmit(curRoot->root->getInstructionRoot(), controlNode);
// FIX-ME no longer need curOutput
DataNode* curOutput = curRoot->root;
// although exception edges are not explicit
// we need to consider them as real outgoing edges
if ((curOutput->hasConsumers() || curOutput->canRaiseException()) && !curOutput->hasKind(vkVoid))
{
// now walk through all vr's assigned to this producer
VirtualRegister* curVR;
Instruction* nextInsn;
switch (curOutput->getKind())
{
case vkCond:
case vkMemory:
nextInsn = curOutput->getInstructionAnnotation();
if (nextInsn)
priorityTopoEmit(nextInsn, controlNode);
break;
case vkLong:
curVR = curOutput->getHighVirtualRegisterAnnotation();
assert(curVR);
nextInsn = curVR->getDefiningInstruction();
if (nextInsn)
priorityTopoEmit(nextInsn, controlNode);
// FALL THROUGH for low vr
case vkAddr:
case vkInt:
case vkFloat:
case vkDouble:
curVR = curOutput->getLowVirtualRegisterAnnotation();
assert(curVR);
nextInsn = curVR->getDefiningInstruction();
if (nextInsn)
priorityTopoEmit(nextInsn, controlNode);
break;
case vkTuple:
case vkVoid:
break;
default:
trespass("unknown or unhandled output");
}
}
}
}
if (anchoredPrimitive)
priorityTopoEmit(anchoredPrimitive->getInstructionRoot(), controlNode);
}
/*
Compute the debugLineNumbers for each Primitive in the CN.
The debugLineNumber assures that the stable sort will not invalidate the scheduled instruction
ordering. Debug line numbers are the minimum integer values which maintain the following
properties: lineNumber(P) <= debugLineNumber(P) and for every Primitive P' which
defines an edge consumed by P, debugLineNumber(P) >= debugLineNumber(P').
*/
void LinearInstructionScheduler::
renumberCN(Vector<RootPair>& roots, ControlNode& /*controlNode*/)
{
RootPair* curRoot;
int rootsToRenumber = roots.size();
int rootsRenumbered = 0;
const DoublyLinkedList<DataConsumer>* consumers;
DoublyLinkedList<DataConsumer> :: iterator curConsumer;
// Initialize all root's renumberData
for(curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
{
if(curRoot->isPrimary)
curRoot->data.renumbered = false;
else {
curRoot->data.renumbered = false;
curRoot->data.timesVisited = 0;
curRoot->data.neededVisits = 0;
if (curRoot->root->getOutgoingEdgesEnd() > curRoot->root->getOutgoingEdgesBegin())
{
DataNode* curOutput;
for (curOutput = curRoot->root->getOutgoingEdgesBegin();
curOutput < curRoot->root->getOutgoingEdgesEnd();
curOutput++)
{
consumers = &curOutput->getConsumers();
for(curConsumer = consumers->begin(); !consumers->done(curConsumer);
curConsumer = consumers->advance(curConsumer))
curRoot->data.neededVisits++;
}
}
}
}
// Renumber Primary Roots
for(curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
{
if(curRoot->isPrimary)
{
curRoot->root->setDebugLineNumber(curRoot->root->getLineNumber());
renumberPrimitive(roots, *(curRoot->root));
rootsRenumbered++;
curRoot->data.renumbered = true;
}
}
curRoot = roots.begin();
while ( rootsRenumbered != rootsToRenumber )
{
while(curRoot->data.renumbered)
{
curRoot++;
if(curRoot == roots.end())
curRoot = roots.begin();
}
if(curRoot->data.timesVisited != curRoot->data.neededVisits)
{
renumberPrimitive(roots, *(curRoot->root));
rootsRenumbered++;
curRoot->data.renumbered = true;
}
curRoot++;
if(curRoot == roots.end())
curRoot = roots.begin();
}
}
void LinearInstructionScheduler::
renumberPrimitive(Vector<RootPair>& roots, Primitive& p)
{
DataConsumer* curConsumer;
for (curConsumer = p.getInputsBegin();
curConsumer < p.getInputsEnd();
curConsumer++)
{
if(curConsumer->isVariable())
{
DataNode& possibleChild = curConsumer->getNode();
if (!possibleChild.hasCategory(pcPhi))
{
Primitive &child = Primitive::cast(possibleChild);
if(child.getDebugLineNumber() == 0)
child.setDebugLineNumber(child.getLineNumber());
if(child.getDebugLineNumber() < p.getDebugLineNumber())
child.setDebugLineNumber(p.getDebugLineNumber());
RootPair* curRoot;
bool isRoot = false;
for(curRoot = roots.begin(); curRoot < roots.end(); curRoot++)
{
if(curRoot->root == &child)
{
isRoot = true;
curRoot->data.timesVisited++;
break;
}
}
if(!isRoot)
renumberPrimitive(roots, child);
}
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// LinearInstructionScheduler.h
//
// Peter DeSantis
// Scott M. Silver
// General Idea:
// preserves the src code ordering
// instructions. It is the result of a topological sort of the control node from each primary
// root. A primary root is one which is not reachable by any other root in the control node.
// When there is more than outgoing edge from a node, they are searched in increasing order of
// their srcLine fields.
#ifndef SCHEDULER_H
#define SCHEDULER_H
#include "CodeGenerator.h"
#include "Vector.h"
class LinearInstructionScheduler
{
public:
void schedule(Vector<RootPair>& roots, ControlNode& controlNode);
protected:
void priorityTopoEmit(Instruction* inInstruction, ControlNode& controlNode);
void renumberCN(Vector<RootPair>& roots, ControlNode& controlNode);
void renumberPrimitive(Vector<RootPair>& roots, Primitive& p);
void linearSchedule(Vector<RootPair>& roots, ControlNode& controlNode);
};
#endif //SCHEDULER_H

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#if !defined(_CPU_INFO_H_) || defined(INCLUDE_EMITTER)
#define _CPU_INFO_H_
#ifdef GENERATE_FOR_PPC
#include "PPC601Cpu.h"
#elif defined(GENERATE_FOR_X86)
#include "x86Win32Cpu.h"
#elif defined(GENERATE_FOR_SPARC)
//#include "SparcCpu.h"
#elif defined(GENERATE_FOR_HPPA)
#include "HPPACpu.h"
#endif
#ifndef CPU_IS_SUPPORTED
#error "Processor not supported"
#endif
#define NUMBER_OF_CALLER_SAVED_GR (LAST_CALLER_SAVED_GR - FIRST_CALLER_SAVED_GR + 1)
#define NUMBER_OF_CALLEE_SAVED_GR (LAST_CALLEE_SAVED_GR - FIRST_CALLEE_SAVED_GR + 1)
#define NUMBER_OF_CALLER_SAVED_FPR (LAST_CALLER_SAVED_FPR - FIRST_CALLER_SAVED_FPR + 1)
#define NUMBER_OF_CALLEE_SAVED_FPR (LAST_CALLEE_SAVED_FPR - FIRST_CALLEE_SAVED_FPR + 1)
#define NUMBER_OF_GREGISTERS (LAST_GREGISTER - FIRST_GREGISTER + 1)
#define NUMBER_OF_FPREGISTERS (LAST_FPREGISTER - FIRST_FPREGISTER + 1)
#define NUMBER_OF_REGISTERS (NUMBER_OF_GREGISTERS + NUMBER_OF_FPREGISTERS + NUMBER_OF_SPECIAL_REGISTERS)
#endif /* _CPU_INFO_H_ */

Просмотреть файл

@ -0,0 +1,53 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ../../..
DIRS = $(CPU_ARCH) $(GENERIC)
SUBMODULES = $(DIRS)
LOCAL_EXPORTS = CpuInfo.h
#######################################################################
# (2) Include "component" configuration information. #
#######################################################################
include $(DEPTH)/config/config.mk
#######################################################################
# (3) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#######################################################################
# (4) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
Generic_Support
*/
#include "NativeCodeCache.h"
#include <stdio.h>
#include "Fundamentals.h"
void* backPatchMethod(void* /*inMethodAddress*/, void* /*inLastPC*/, void* /*inUserDefined*/)
{
trespass("not implemented");
return (NULL);
}
static void dummyStub();
static void dummyStub()
{
printf("dummyStub #1\n");
}
void*
generateCompileStub(NativeCodeCache& /*inCache*/, const CacheEntry& /*inCacheEntry*/)
{
#ifndef GENERATE_FOR_PPC
return ((void*) dummyStub);
#else
return (*(void**) dummyStub);
#endif
}

Просмотреть файл

@ -0,0 +1,60 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ../../../..
CPPSRCS = Generic_Support.cpp \
$(NULL)
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################

Просмотреть файл

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HPPA_CPU_H_
#define _HPPA_CPU_H_
#define FIRST_CALLER_SAVED_GR 0
#define LAST_CALLER_SAVED_GR 12
#define FIRST_CALLEE_SAVED_GR 13
#define LAST_CALLEE_SAVED_GR 28
#define FIRST_CALLER_SAVED_FPR 29
#define LAST_CALLER_SAVED_FPR 56
#define FIRST_CALLEE_SAVED_FPR 57
#define LAST_CALLEE_SAVED_FPR 76
#define FIRST_GREGISTER 0
#define LAST_GREGISTER 28
#define FIRST_FPREGISTER 29
#define LAST_FPREGISTER 76
#define NUMBER_OF_SPECIAL_REGISTERS 3
#define HAS_GR_PAIRS
#define HAS_FPR_PAIRS
#define DOUBLE_WORD_GR_ALIGNMENT
#undef SOFT_FLOAT
#undef SINGLE_WORD_FPR_ALIGNMENT
#define SINGLE_WORD_FPR_SIZE 1
#define DOUBLE_WORD_FPR_ALIGNMENT
#define DOUBLE_WORD_FPR_SIZE 2
#define QUAD_WORD_FPR_ALIGNMENT
#define QUAD_WORD_FPR_SIZE 4
#define CPU_IS_SUPPORTED
#if defined(INCLUDE_EMITTER)
#include "HPPAEmitter.h"
typedef HPPAEmitter MdEmitter;
#endif /* INCLUDE_EMITTER */
#endif /* _HPPA_CPU_H_ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HPPA_EMITTER_H_
#define _HPPA_EMITTER_H_
#include "InstructionEmitter.h"
#include "HPPAInstruction.h"
#include "VirtualRegister.h"
#include "FastBitSet.h"
class PrimArg;
class Pool;
#define UNDEFINED_RULE(inRuleKind) \
case inRuleKind: \
PR_ASSERT(false); \
break;
#define UNIMP_CODE(a)
/*
*-----------------------------------------------------------------------
*
* HPPA-1.1 Instruction Emitter.
*
*-----------------------------------------------------------------------
*/
class HPPAEmitter : public InstructionEmitter
{
protected:
Instruction& genInstruction(DataNode* inPrimitive, Pool& inPool, HPPAInstructionKind kind, PRUint32 data = 0);
void emitInstruction(Primitive& inPrimitive, HPPAInstructionKind kind);
void emitCondBranch(Primitive& inPrimitive, HPPAConditionKind kind);
void emitOrImm(Primitive& inPrimitive, const Value& value);
void emitAndImm(Primitive& inPrimitive, const Value& value);
void emitXorImm(Primitive& inPrimitive, const Value& value);
void emitAddImm(DataNode& inPrimitive, const Value& value);
void emitDivImm(Primitive& inPrimitive, const Value& value);
void emitMulImm(Primitive& inPrimitive, const Value& value);
void emitShlImm(Primitive& inPrimitive, const Value& value);
void emitConst(Primitive& inPrimitive, const Value& value);
void emitResult(Primitive& inPrimitive);
void emitChkNull(Primitive& inPrimitive);
void emitLimitR(Primitive& inPrimitive);
void emitLimit(Primitive& inPrimitive);
void emitLoad(Primitive& inPrimitive, HPPAInstructionFlags flags = HPPA_NONE);
void emitLoadFromImm(Primitive& inPrimitive, HPPAInstructionFlags flags = HPPA_NONE);
void emitStore(Primitive& inPrimitive, HPPAInstructionFlags flags = HPPA_NONE);
void emitStoreImm(Primitive& inPrimitive, HPPAInstructionFlags flags = HPPA_NONE);
void emitStoreToImm(Primitive& inPrimitive, HPPAInstructionFlags flags = HPPA_NONE);
void emitStoreImmToImm(Primitive& inPrimitive, HPPAInstructionFlags flags = HPPA_NONE);
void emitShAddIndirect(Primitive& inPrimitive);
void emitSpecialCall(Primitive& inPrimitive, HPPASpecialCallKind kind);
VirtualRegister& genLoadConstant(DataNode& inPrimitive, const Value& value, bool checkIM14 = true);
VirtualRegister& genShiftAdd(Primitive& inPrimitive, const PRUint8 shiftBy, VirtualRegister& shiftedReg, VirtualRegister& addedReg);
VirtualRegister& genShiftSub(Primitive& inPrimitive, const PRUint8 shiftBy, VirtualRegister& shiftedReg, VirtualRegister& subtractedReg, bool neg = false);
static void initSpecialCall();
static bool initSpecialCallDone;
public:
HPPAEmitter(Pool& inPool, VirtualRegisterManager& vrMan) : InstructionEmitter(inPool, vrMan)
{
if (!initSpecialCallDone)
{
initSpecialCallDone = true;
initSpecialCall();
}
}
virtual void emitPrimitive(Primitive& inPrimitive, NamedRule inRule);
void calculatePrologEpilog(Method& /*inMethod*/, uint32& outPrologSize, uint32& outEpilogSize) {outPrologSize = 32; outEpilogSize = 4;}
virtual void formatPrologToMemory(void* inWhere);
virtual void formatEpilogToMemory(void* inWhere) {*(PRUint32*)inWhere = 0xe840c002; /* bv,n 0(%rp) */}
virtual void emitArgument(PrimArg& /*inArguments*/, const PRUint32 /*inArgumentIndex*/) {}
virtual void emitArguments(ControlBegin& inBeginNode);
virtual Instruction& emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget);
virtual bool emitCopyAfter(DataNode& inDataNode, SortedDoublyLinkedList<Instruction>::iterator where, VirtualRegister& fromVr, VirtualRegister& toVr);
virtual void emitLoadAfter(DataNode& /*inDataNode*/, SortedDoublyLinkedList<Instruction>::iterator /*where*/, VirtualRegister& /*loadedReg*/, VirtualRegister& /*stackReg*/) {}
virtual void emitStoreAfter(DataNode& /*inDataNode*/, SortedDoublyLinkedList<Instruction>::iterator /*where*/, VirtualRegister& /*storedReg*/, VirtualRegister& /*stackReg*/) {}
};
#endif /* _HPPA_EMITTER_H_ */

Просмотреть файл

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HPPA_FUNCS_H_
#define _HPPA_FUNCS_H_
#include "prtypes.h"
#if defined(hppa)
#define HPPAFuncAddress(func) (func)
#else
#define HPPAFuncAddress(func) NULL
#endif /* defined(hppa) */
PR_BEGIN_EXTERN_C
extern PRUint32* HPPASpecialCodeBegin;
extern PRUint32* HPPASpecialCodeEnd;
extern PRUint32* HPPAremI;
extern PRUint32* HPPAremU;
extern PRUint32* HPPAdivI;
extern PRUint32* HPPAdivU;
PR_END_EXTERN_C
#endif /* _HPPA_FUNCS_H_ */

Просмотреть файл

@ -0,0 +1,694 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
.SPACE $PRIVATE$
.SUBSPA $DATA$
.align 4
.EXPORT HPPAremI,DATA
HPPAremI:
.long _remI
.EXPORT HPPAremU,DATA
HPPAremU:
.long _remU
.EXPORT HPPAdivI,DATA
HPPAdivI:
.long _divI
.EXPORT HPPAdivU,DATA
HPPAdivU:
.long _divU
.EXPORT HPPASpecialCodeBegin,DATA
HPPASpecialCodeBegin:
.long _begin
.EXPORT HPPASpecialCodeEnd,DATA
HPPASpecialCodeEnd:
.long _end
.SPACE $TEXT$
.SUBSPA $CODE$
.align 4
_begin:
_remI:
addit,= 0,%arg1,%r0
add,>= %r0,%arg0,%ret1
sub %r0,%ret1,%ret1
sub %r0,%arg1,%r1
ds %r0,%r1,%r0
copy %r0,%r1
add %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
movb,>=,n %r1,%ret1,L5
add,< %arg1,%r0,%r0
add,tr %r1,%arg1,%ret1
sub %r1,%arg1,%ret1
L5: add,>= %arg0,%r0,%r0
sub %r0,%ret1,%ret1
bv %r0(%r31)
nop
.align 4
_remU:
comibf,<,n 0x0,%arg1,_remU_special_case
sub %r0,%arg1,%ret1
ds %r0,%ret1,%r0
add %arg0,%arg0,%r1
ds %r0,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
addc %r1,%r1,%r1
ds %ret1,%arg1,%ret1
comiclr,<= 0,%ret1,%r0
add %ret1,%arg1,%ret1
bv,n %r0(%r31)
nop
_remU_special_case:
addit,= 0,%arg1,%r0
sub,>>= %arg0,%arg1,%ret1
copy %arg0,%ret1
bv,n %r0(%r31)
nop
.align 4
_divI:
comibf,<<,n 0xf,%arg1,_divI_small_divisor
add,>= %r0,%arg0,%ret1
_divI_normal:
sub %r0,%ret1,%ret1
sub %r0,%arg1,%r1
ds %r0,%r1,%r0
add %ret1,%ret1,%ret1
ds %r0,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
xor,>= %arg0,%arg1,%r0
sub %r0,%ret1,%ret1
bv,n %r0(%r31)
nop
_divI_small_divisor:
blr,n %arg1,%r0
nop
addit,= 0,%arg1,%r0
nop
bv %r0(%r31)
copy %arg0,%ret1
b,n _divI_2
nop
b,n _divI_3
nop
b,n _divI_4
nop
b,n _divI_5
nop
b,n _divI_6
nop
b,n _divI_7
nop
b,n _divI_8
nop
b,n _divI_9
nop
b,n _divI_10
nop
b _divI_normal
add,>= %r0,%arg0,%ret1
b,n _divI_12
nop
b _divI_normal
add,>= %r0,%arg0,%ret1
b,n _divI_14
nop
b,n _divI_15
nop
.align 4
_divU:
comibf,< 0xf,%arg1,_divU_special_divisor
sub %r0,%arg1,%r1
ds %r0,%r1,%r0
_divU_normal:
add %arg0,%arg0,%ret1
ds %r0,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
addc %ret1,%ret1,%ret1
ds %r1,%arg1,%r1
bv %r0(%r31)
addc %ret1,%ret1,%ret1
_divU_special_divisor:
comibf,<= 0,%arg1,_divU_big_divisor
nop
blr %arg1,%r0
nop
_divU_small_divisor:
addit,= 0,%arg1,%r0
nop
bv %r0(%r31)
copy %arg0,%ret1
bv %r0(%r31)
extru %arg0,30,31,%ret1
b,n _divU_3
nop
bv %r0(%r31)
extru %arg0,29,30,%ret1
b,n _divU_5
nop
b,n _divU_6
nop
b,n _divU_7
nop
bv %r0(%r31)
extru %arg0,28,29,%ret1
b,n _divU_9
nop
b,n _divU_10
nop
b _divU_normal
ds %r0,%r1,%r0
b,n _divU_12
nop
b _divU_normal
ds %r0,%r1,%r0
b,n _divU_14
nop
b,n _divU_15
nop
_divU_big_divisor:
sub %arg0,%arg1,%r0
bv %r0(%r31)
addc %r0,%r0,%ret1
_divI_2:
comclr,>= %arg0,%r0,%r0
addi 1,%arg0,%arg0
bv %r0(%r31)
extrs %arg0,30,31,%ret1
_divI_4:
comclr,>= %arg0,%r0,%r0
addi 3,%arg0,%arg0
bv %r0(%r31)
extrs %arg0,29,30,%ret1
_divI_8:
comclr,>= %arg0,%r0,%r0
addi 7,%arg0,%arg0
bv %r0(%r31)
extrs %arg0,28,29,%ret1
_divI_3:
comb,<,n %arg0,%r0,_divI_neg3
addi 1,%arg0,%arg0
extru %arg0,1,2,%ret1
sh2add %arg0,%arg0,%arg0
b _divI_pos
addc %ret1,%r0,%ret1
_divI_neg3:
subi 1,%arg0,%arg0
extru %arg0,1,2,%ret1
sh2add %arg0,%arg0,%arg0
b _divI_neg
addc %ret1,%r0,%ret1
_divU_3:
addi 1,%arg0,%arg0
addc %r0,%r0,%ret1
shd %ret1,%arg0,30,%arg1
sh2add %arg0,%arg0,%arg0
b _divI_pos
addc %ret1,%arg1,%ret1
_divI_5:
comb,<,n %arg0,%r0,_divI_neg5
addi 3,%arg0,%arg1
sh1add %arg0,%arg1,%arg0
b _divI_pos
addc %r0,%r0,%ret1
_divI_neg5:
sub %r0,%arg0,%arg0
addi 1,%arg0,%arg0
shd %r0,%arg0,31,%ret1
sh1add %arg0,%arg0,%arg0
b _divI_neg
addc %ret1,%r0,%ret1
_divU_5:
addi 1,%arg0,%arg0
addc %r0,%r0,%ret1
shd %ret1,%arg0,31,%arg1
sh1add %arg0,%arg0,%arg0
b _divI_pos
addc %arg1,%ret1,%ret1
_divI_6:
comb,<,n %arg0,%r0,_divI_neg6
extru %arg0,30,31,%arg0
addi 5,%arg0,%arg1
sh2add %arg0,%arg1,%arg0
b _divI_pos
addc %r0,%r0,%ret1
_divI_neg6:
subi 2,%arg0,%arg0
extru %arg0,30,31,%arg0
shd %r0,%arg0,30,%ret1
sh2add %arg0,%arg0,%arg0
b _divI_neg
addc %ret1,%r0,%ret1
_divU_6:
extru %arg0,30,31,%arg0
addi 1,%arg0,%arg0
shd %r0,%arg0,30,%ret1
sh2add %arg0,%arg0,%arg0
b _divI_pos
addc %ret1,%r0,%ret1
_divI_10:
comb,< %arg0,%r0,_divI_neg10
copy %r0,%ret1
extru %arg0,30,31,%arg0
addibf 1,%arg0,_divI_pos
sh1add %arg0,%arg0,%arg0
_divI_neg10:
subi 2,%arg0,%arg0
extru %arg0,30,31,%arg0
sh1add %arg0,%arg0,%arg0
_divI_neg:
shd %ret1,%arg0,28,%arg1
shd %arg0,%r0,28,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
shd %ret1,%arg0,24,%arg1
shd %arg0,%r0,24,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
shd %ret1,%arg0,16,%arg1
shd %arg0,%r0,16,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
bv %r0(%r31)
sub %r0,%ret1,%ret1
_divU_10:
extru %arg0,30,31,%arg0
addi 3,%arg0,%arg1
sh1add %arg0,%arg1,%arg0
addc %r0,%r0,%ret1
_divI_pos:
shd %ret1,%arg0,28,%arg1
_divI_pos_for_15:
shd %arg0,%r0,28,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
shd %ret1,%arg0,24,%arg1
shd %arg0,%r0,24,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
shd %ret1,%arg0,16,%arg1
shd %arg0,%r0,16,%r1
add %arg0,%r1,%arg0
bv %r0(%r31)
addc %ret1,%arg1,%ret1
_divI_12:
comb,< %arg0,%r0,_divI_neg12
copy %r0,%ret1
extru %arg0,29,30,%arg0
addibf 1,%arg0,_divI_pos
sh2add %arg0,%arg0,%arg0
_divI_neg12:
subi 4,%arg0,%arg0
extru %arg0,29,30,%arg0
b _divI_neg
sh2add %arg0,%arg0,%arg0
_divU_12:
extru %arg0,29,30,%arg0
addi 5,%arg0,%arg1
sh2add %arg0,%arg1,%arg0
b _divI_pos
addc %r0,%r0,%ret1
_divI_15:
comb,< %arg0,%r0,_divI_neg15
copy %r0,%ret1
addibf 1,%arg0,_divI_pos_for_15
shd %ret1,%arg0,28,%arg1
_divI_neg15:
b _divI_neg
subi 1,%arg0,%arg0
_divU_15:
addi 1,%arg0,%arg0
b _divI_pos
addc %r0,%r0,%ret1
_divI_7:
comb,<,n %arg0,%r0,_divI_neg7
_divI_7a:
addi 1,%arg0,%arg0
shd %r0,%arg0,29,%ret1
sh3add %arg0,%arg0,%arg0
addc %ret1,%r0,%ret1
_divI_pos7:
shd %ret1,%arg0,26,%arg1
shd %arg0,%r0,26,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
shd %ret1,%arg0,20,%arg1
shd %arg0,%r0,20,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%arg1
copy %r0,%ret1
shd,= %arg1,%arg0,24,%arg1
L1: addbf %arg1,%ret1,L2
extru %arg0,31,24,%arg0
bv,n %r0(%r31)
L2: addbf %arg1,%arg0,L1
extru,= %arg0,7,8,%arg1
_divI_neg7:
subi 1,%arg0,%arg0
_divI_neg7a:
shd %r0,%arg0,29,%ret1
sh3add %arg0,%arg0,%arg0
addc %ret1,%r0,%ret1
_divI_neg7_shift:
shd %ret1,%arg0,26,%arg1
shd %arg0,%r0,26,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%ret1
shd %ret1,%arg0,20,%arg1
shd %arg0,%r0,20,%r1
add %arg0,%r1,%arg0
addc %ret1,%arg1,%arg1
copy %r0,%ret1
shd,= %arg1,%arg0,24,%arg1
L3: addbf %arg1,%ret1,L4
extru %arg0,31,24,%arg0
bv %r0(%r31)
sub %r0,%ret1,%ret1
L4: addbf %arg1,%arg0,L3
extru,= %arg0,7,8,%arg1
_divU_7:
addi 1,%arg0,%arg0
addc %r0,%r0,%ret1
shd %ret1,%arg0,29,%arg1
sh3add %arg0,%arg0,%arg0
b _divI_pos7
addc %arg1,%ret1,%ret1
_divI_9:
comb,<,n %arg0,%r0,_divI_neg9
addi 1,%arg0,%arg0
shd %r0,%arg0,29,%arg1
shd %arg0,%r0,29,%r1
sub %r1,%arg0,%arg0
b _divI_pos7
subb %arg1,%r0,%ret1
_divI_neg9:
subi 1,%arg0,%arg0
shd %r0,%arg0,29,%arg1
shd %arg0,%r0,29,%r1
sub %r1,%arg0,%arg0
b _divI_neg7_shift
subb %arg1,%r0,%ret1
_divU_9:
addi 1,%arg0,%arg0
addc %r0,%r0,%ret1
shd %ret1,%arg0,29,%arg1
shd %arg0,%r0,29,%r1
sub %r1,%arg0,%arg0
b _divI_pos7
subb %arg1,%ret1,%ret1
_divI_14:
comb,<,n %arg0,%r0,_divI_neg14
_divU_14:
b _divI_7a
extru %arg0,30,31,%arg0
_divI_neg14:
subi 2,%arg0,%arg0
b _divI_neg7a
extru %arg0,30,31,%arg0
_end:

Просмотреть файл

@ -0,0 +1,677 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HPPAInstruction.h"
#include "HPPAFuncs.h"
#include "ControlNodes.h"
HPPAInstructionInfo hiInfo[nHPPAInstructionKind] =
{
{ ADD, 0x02, 0x18, 6, "add", HPPA_NONE }, // *****
{ ADDBF, 0xff, 0x00, 0, "addbf", HPPA_UNIMP },
{ ADDBT, 0xff, 0x00, 0, "addbt", HPPA_UNIMP },
{ ADDO, 0xff, 0x00, 0, "addo", HPPA_UNIMP },
{ ADDIBF, 0xff, 0x00, 0, "addibf", HPPA_UNIMP },
{ ADDIBT, 0xff, 0x00, 0, "addibt", HPPA_UNIMP },
{ ADDIL, 0xff, 0x00, 0, "addil", HPPA_UNIMP },
{ ADDL, 0x02, 0x28, 6, "addl", HPPA_NONE }, // *****
{ ADDI, 0xff, 0x00, 0, "addi", HPPA_UNIMP },
{ ADDIT, 0xff, 0x00, 0, "addit", HPPA_UNIMP },
{ ADDITO, 0xff, 0x00, 0, "addito", HPPA_UNIMP },
{ ADDC, 0xff, 0x00, 0, "addc", HPPA_UNIMP },
{ ADDCO, 0xff, 0x00, 0, "addco", HPPA_UNIMP },
{ AND, 0x02, 0x08, 6, "and", HPPA_NONE }, // *****
{ ANDCM, 0xff, 0x00, 0, "andcm", HPPA_UNIMP },
{ BL, 0x3a, 0x00, 13, "bl", HPPA_NONE }, // *****
{ BLE, 0xff, 0x00, 0, "ble", HPPA_UNIMP },
{ BLR, 0xff, 0x00, 0, "blr", HPPA_UNIMP },
{ BE, 0xff, 0x00, 0, "be", HPPA_UNIMP },
{ BB, 0xff, 0x00, 0, "bb", HPPA_UNIMP },
{ BVB, 0xff, 0x00, 0, "bvb", HPPA_UNIMP },
{ BV, 0xff, 0x00, 0, "bv", HPPA_UNIMP },
{ BREAK, 0xff, 0x00, 0, "break", HPPA_UNIMP },
{ COMBF, 0x22, 0x00, 11, "combf", HPPA_NONE }, // *****
{ COMBT, 0x20, 0x00, 11, "combt", HPPA_NONE }, // *****
{ COMCLR, 0xff, 0x00, 0, "comclr", HPPA_UNIMP },
{ COMIBF, 0x23, 0x00, 0, "comibf", HPPA_DATA_HAS_IM5 }, // *****
{ COMIBT, 0x21, 0x00, 11, "comibt", HPPA_DATA_HAS_IM5 }, // *****
{ COMICLR, 0xff, 0x00, 0, "comiclr", HPPA_UNIMP },
{ CLDDX, 0xff, 0x00, 0, "clddx", HPPA_UNIMP },
{ CLDDS, 0xff, 0x00, 0, "cldds", HPPA_UNIMP },
{ CLDWX, 0xff, 0x00, 0, "cldwx", HPPA_UNIMP },
{ CLDWS, 0xff, 0x00, 0, "cldws", HPPA_UNIMP },
{ COPR, 0xff, 0x00, 0, "copr", HPPA_UNIMP },
{ CSTDX, 0xff, 0x00, 0, "cstdx", HPPA_UNIMP },
{ CSTDS, 0xff, 0x00, 0, "cstds", HPPA_UNIMP },
{ CSTWX, 0xff, 0x00, 0, "cstwx", HPPA_UNIMP },
{ CSTWS, 0xff, 0x00, 0, "cstws", HPPA_UNIMP },
{ COPY, 0x02, 0x09, 6, "copy", HPPA_R1_IS_ZERO | HPPA_IS_COPY }, // *****
{ DCOR, 0xff, 0x00, 0, "dcor", HPPA_UNIMP },
{ DEP, 0xff, 0x00, 0, "dep", HPPA_UNIMP },
{ DEPI, 0x35, 0x07, 9, "depi", HPPA_DATA_HAS_IM5 }, // *****
{ DIAG, 0xff, 0x00, 0, "diag", HPPA_UNIMP },
{ DS, 0xff, 0x00, 0, "ds", HPPA_UNIMP },
{ XOR, 0x02, 0x0a, 6, "xor", HPPA_NONE }, // ****
{ EXTRS, 0x34, 0x07, 8, "extrs", HPPA_NONE }, // *****
{ EXTRU, 0x34, 0x06, 8, "extru", HPPA_NONE }, // *****
{ XMPYU, 0x0e, 0x00, 40, "xmpyu", HPPA_NONE },
{ FABS, 0xff, 0x00, 0, "fabs", HPPA_UNIMP },
{ FCMP, 0xff, 0x00, 0, "fcmp", HPPA_UNIMP },
{ FCNVXF, 0xff, 0x00, 0, "fcnvxf", HPPA_UNIMP },
{ FCNVFX, 0xff, 0x00, 0, "fcnvfx", HPPA_UNIMP },
{ FCNVFXT, 0xff, 0x00, 0, "fcnvfxt", HPPA_UNIMP },
{ FCNVFF, 0xff, 0x00, 0, "fcnvff", HPPA_UNIMP },
{ FDIV, 0xff, 0x00, 0, "fdiv", HPPA_UNIMP },
{ FLDDX, 0xff, 0x00, 0, "flddx", HPPA_UNIMP },
{ FLDDS, 0xff, 0x00, 0, "fldds", HPPA_UNIMP },
{ FLDWX, 0xff, 0x00, 0, "fldwx", HPPA_UNIMP },
{ FLDWS, 0x09, 0x00, 31, "fldws", HPPA_DATA_HAS_IM5 }, // *****
{ FMPY, 0xff, 0x00, 0, "fmpy", HPPA_UNIMP },
{ FMPYADD, 0xff, 0x00, 0, "fmpyadd", HPPA_UNIMP },
{ FMPYSUB, 0xff, 0x00, 0, "fmpysub", HPPA_UNIMP },
{ FRND, 0xff, 0x00, 0, "frnd", HPPA_UNIMP },
{ FSQRT, 0xff, 0x00, 0, "fsqrt", HPPA_UNIMP },
{ FSTDX, 0xff, 0x00, 0, "fstdx", HPPA_UNIMP },
{ FSTDS, 0xff, 0x00, 0, "fstds", HPPA_UNIMP },
{ FSTWS, 0x09, 0x00, 32, "fstws", HPPA_DATA_HAS_IM5 }, // *****
{ FSUB, 0xff, 0x00, 0, "fsub", HPPA_UNIMP },
{ FTEST, 0xff, 0x00, 0, "ftest", HPPA_UNIMP },
{ FDC, 0xff, 0x00, 0, "fdc", HPPA_UNIMP },
{ FDCE, 0xff, 0x00, 0, "fdce", HPPA_UNIMP },
{ FIC, 0xff, 0x00, 0, "fic", HPPA_UNIMP },
{ FICE, 0xff, 0x00, 0, "fice", HPPA_UNIMP },
{ GATE, 0xff, 0x00, 0, "gate", HPPA_UNIMP },
{ DEBUGID, 0xff, 0x00, 0, "debugid", HPPA_UNIMP },
{ OR, 0x02, 0x09, 6, "or", HPPA_NONE }, // *****
{ IDTLBA, 0xff, 0x00, 0, "idtlba", HPPA_UNIMP },
{ IDTLBP, 0xff, 0x00, 0, "idtlbp", HPPA_UNIMP },
{ IITLBA, 0xff, 0x00, 0, "iitlba", HPPA_UNIMP },
{ IITLBP, 0xff, 0x00, 0, "iitlbp", HPPA_UNIMP },
{ IDCOR, 0xff, 0x00, 0, "idcor", HPPA_UNIMP },
{ LDCWX, 0xff, 0x00, 0, "ldcwx", HPPA_UNIMP },
{ LDCWS, 0xff, 0x00, 0, "ldcws", HPPA_UNIMP },
{ LDB, 0xff, 0x00, 0, "ldb", HPPA_UNIMP },
{ LDBX, 0xff, 0x00, 0, "ldbx", HPPA_UNIMP },
{ LDBS, 0xff, 0x00, 0, "ldbs", HPPA_UNIMP },
{ LCI, 0xff, 0x00, 0, "lci", HPPA_UNIMP },
{ LDH, 0xff, 0x00, 0, "ldh", HPPA_UNIMP },
{ LDHX, 0xff, 0x00, 0, "ldhx", HPPA_UNIMP },
{ LDHS, 0xff, 0x00, 0, "ldhs", HPPA_UNIMP },
{ LDI, 0x0d, 0x00, 1, "ldi", HPPA_DATA_HAS_IM14 | HPPA_R1_IS_ZERO }, // *****
{ LDIL, 0x08, 0x00, 5, "ldil", HPPA_DATA_HAS_IM21 }, // *****
{ LDO, 0x0d, 0x00, 1, "ldo", HPPA_DATA_HAS_IM14 }, // *****
{ LPA, 0xff, 0x00, 0, "lpa", HPPA_UNIMP },
{ LDSID, 0xff, 0x00, 0, "ldsid", HPPA_UNIMP },
{ LDW, 0x12, 0x00, 1, "ldw", HPPA_DATA_HAS_IM14 }, // *****
{ LDWAX, 0xff, 0x00, 0, "ldwax", HPPA_UNIMP },
{ LDWAS, 0xff, 0x00, 0, "ldwas", HPPA_UNIMP },
{ LDWM, 0xff, 0x00, 0, "ldwm", HPPA_UNIMP },
{ LDWX, 0xff, 0x00, 0, "ldwx", HPPA_UNIMP },
{ LDWS, 0xff, 0x00, 0, "ldws", HPPA_UNIMP },
{ MOVB, 0xff, 0x00, 0, "movb", HPPA_UNIMP },
{ MFCTL, 0xff, 0x00, 0, "mfctl", HPPA_UNIMP },
{ MFDBAM, 0xff, 0x00, 0, "mfdbam", HPPA_UNIMP },
{ MFDBAO, 0xff, 0x00, 0, "mfdbao", HPPA_UNIMP },
{ MFIBAM, 0xff, 0x00, 0, "mfibam", HPPA_UNIMP },
{ MFIBAO, 0xff, 0x00, 0, "mfibao", HPPA_UNIMP },
{ MFSP, 0xff, 0x00, 0, "mfsp", HPPA_UNIMP },
{ MOVIB, 0xff, 0x00, 0, "movib", HPPA_UNIMP },
{ MCTL, 0xff, 0x00, 0, "mctl", HPPA_UNIMP },
{ MTBAM, 0xff, 0x00, 0, "mtbam", HPPA_UNIMP },
{ MTBAO, 0xff, 0x00, 0, "mtbao", HPPA_UNIMP },
{ MTIBAM, 0xff, 0x00, 0, "mtibam", HPPA_UNIMP },
{ MTIBAO, 0xff, 0x00, 0, "mtibao", HPPA_UNIMP },
{ MTSP, 0xff, 0x00, 0, "mtsp", HPPA_UNIMP },
{ MTSM, 0xff, 0x00, 0, "mtsm", HPPA_UNIMP },
{ PMDIS, 0xff, 0x00, 0, "pmdis", HPPA_UNIMP },
{ PMENB, 0xff, 0x00, 0, "pmenb", HPPA_UNIMP },
{ PROBER, 0xff, 0x00, 0, "prober", HPPA_UNIMP },
{ PROBERI, 0xff, 0x00, 0, "proberi", HPPA_UNIMP },
{ PROBEW, 0xff, 0x00, 0, "probew", HPPA_UNIMP },
{ PROBEWI, 0xff, 0x00, 0, "probewi", HPPA_UNIMP },
{ PDC, 0xff, 0x00, 0, "pdc", HPPA_UNIMP },
{ PDTLB, 0xff, 0x00, 0, "pdtlb", HPPA_UNIMP },
{ PDTLBE, 0xff, 0x00, 0, "pdtlbe", HPPA_UNIMP },
{ PITLB, 0xff, 0x00, 0, "pitlb", HPPA_UNIMP },
{ PITLBE, 0xff, 0x00, 0, "pitlbe", HPPA_UNIMP },
{ RSM, 0xff, 0x00, 0, "rsm", HPPA_UNIMP },
{ RFI, 0xff, 0x00, 0, "rfi", HPPA_UNIMP },
{ RFIR, 0xff, 0x00, 0, "rfir", HPPA_UNIMP },
{ SSM, 0xff, 0x00, 0, "ssm", HPPA_UNIMP },
{ SHD, 0xff, 0x00, 0, "shd", HPPA_UNIMP },
{ SH1ADD, 0xff, 0x00, 0, "sh1add", HPPA_UNIMP },
{ SH1ADDL, 0x02, 0x29, 6, "sh1addl", HPPA_NONE }, // *****
{ SH1ADDO, 0xff, 0x00, 0, "sh1addo", HPPA_UNIMP },
{ SH2ADD, 0xff, 0x00, 0, "sh2add", HPPA_UNIMP },
{ SH2ADDL, 0x02, 0x2a, 6, "sh2addl", HPPA_NONE }, // *****
{ SH2ADDO, 0xff, 0x00, 0, "sh2addo", HPPA_UNIMP },
{ SH3ADD, 0xff, 0x00, 0, "sh3add", HPPA_UNIMP },
{ SH3ADDL, 0x02, 0x2b, 6, "sh3addl", HPPA_NONE }, // *****
{ SH3ADDO, 0xff, 0x00, 0, "sh3addo", HPPA_UNIMP },
{ SPOP0, 0xff, 0x00, 0, "spop0", HPPA_UNIMP },
{ SPOP1, 0xff, 0x00, 0, "spop1", HPPA_UNIMP },
{ SPOP2, 0xff, 0x00, 0, "spop2", HPPA_UNIMP },
{ SPOP3, 0xff, 0x00, 0, "spop3", HPPA_UNIMP },
{ STB, 0xff, 0x00, 0, "stb", HPPA_UNIMP },
{ STBS, 0xff, 0x00, 0, "stbs", HPPA_UNIMP },
{ STBYS, 0xff, 0x00, 0, "stbys", HPPA_UNIMP },
{ STH, 0xff, 0x00, 0, "sth", HPPA_UNIMP },
{ STHS, 0xff, 0x00, 0, "sths", HPPA_UNIMP },
{ STW, 0x1a, 0x00, 1, "stw", HPPA_DATA_HAS_IM14 }, // *****
{ STWAS, 0xff, 0x00, 0, "stwas", HPPA_UNIMP },
{ STWM, 0xff, 0x00, 0, "stwm", HPPA_UNIMP },
{ STWS, 0xff, 0x00, 0, "stws", HPPA_UNIMP },
{ SUB, 0x02, 0x10, 6, "sub", HPPA_NONE }, // *****
{ SUBT, 0xff, 0x00, 0, "subt", HPPA_UNIMP },
{ SUBTO, 0xff, 0x00, 0, "subto", HPPA_UNIMP },
{ SUBO, 0xff, 0x00, 0, "subo", HPPA_UNIMP },
{ SUBI, 0xff, 0x00, 0, "subi", HPPA_UNIMP },
{ SUBIO, 0xff, 0x00, 0, "subio", HPPA_UNIMP },
{ SUBB, 0xff, 0x00, 0, "subb", HPPA_UNIMP },
{ SUBBO, 0xff, 0x00, 0, "subbo", HPPA_UNIMP },
{ SYNC, 0xff, 0x00, 0, "sync", HPPA_UNIMP },
{ SYNCDMA, 0xff, 0x00, 0, "syncdma", HPPA_UNIMP },
{ UADDCM, 0xff, 0x00, 0, "uaddcm", HPPA_UNIMP },
{ UADDCMT, 0xff, 0x00, 0, "uaddcmt", HPPA_UNIMP },
{ UXOR, 0xff, 0x00, 0, "uxor", HPPA_UNIMP },
{ VDEP, 0xff, 0x00, 0, "vdep", HPPA_UNIMP },
{ VDEPI, 0xff, 0x00, 0, "vdepi", HPPA_UNIMP },
{ VEXTRU, 0xff, 0x00, 0, "vextru", HPPA_UNIMP },
{ VSHD, 0xff, 0x00, 0, "vshd", HPPA_UNIMP },
{ ZDEP, 0x35, 0x02, 9, "zdep", HPPA_R1_IS_ZERO }, // *****
{ ZDEPI, 0xff, 0x00, 0, "zdepi", HPPA_UNIMP },
{ ZVDEP, 0xff, 0x00, 0, "zvdep", HPPA_UNIMP },
{ ZVDEPI, 0xff, 0x00, 0, "zvdepi", HPPA_UNIMP }
};
HPPAConditionInfo hcInfo[nHPPAConditionKind] =
{
{ hcNever, hcNever, 0, false, "" },
{ hcE, hcE, 1, false, "=" },
{ hcL, hcGe, 2, false, "<" },
{ hcLe, hcG, 3, false, "<=" },
{ hcLu, hcGeu, 4, false, "<<" },
{ hcLeu, hcGu, 5, false, "<<=" },
{ hcOver, hcOver, 6, false, "SV" },
{ hcOdd, hcOdd, 7, false, "OD" },
{ hcAlways, hcAlways, 0, true, "TR" },
{ hcNe, hcNe, 1, true, "<>" },
{ hcGe, hcL, 2, true, ">=" },
{ hcG, hcLe, 3, true, ">" },
{ hcGeu, hcLu, 4, true, ">>=" },
{ hcGu, hcLeu, 5, true, ">>" },
{ hcNOver, hcNOver, 6, true, "NSV" },
{ hcEven, hcEven, 7, true, "EV" }
};
char* registerNumberToString[] =
{
// General registers
"0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
"%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%arg3",
"%arg2", "%arg1", "%arg0", "%dp", "%ret0", "%ret1", "%sp", "%r31",
// Floating point registers
"%fr0L", "%fr0R", "%fr1L", "%fr1R", "%fr2L", "%fr2R", "%fr3L", "%fr3R",
"%fr4L", "%fr4R", "%fr5L", "%fr5R", "%fr6L", "%fr6R", "%fr7L", "%fr7R",
"%fr8L", "%fr8R", "%fr9L", "%fr9R", "%fr10L", "%fr10R", "%fr11L", "%fr11R",
"%fr12L", "%fr12R", "%fr13L", "%fr13R", "%fr14L", "%fr14R", "%fr15L", "%fr15R",
"%fr16L", "%fr16R", "%fr17L", "%fr17R", "%fr18L", "%fr18R", "%fr19L", "%fr19R",
"%fr20L", "%fr20R", "%fr21L", "%fr21R", "%fr22L", "%fr22R", "%fr23L", "%fr23R",
"%fr24L", "%fr24R", "%fr25L", "%fr25R", "%fr26L", "%fr26R", "%fr27L", "%fr27R",
"%fr28L", "%fr28R", "%fr29L", "%fr29R", "%fr30L", "%fr30R", "%fr31L", "%fr31R",
// Other strings
"%fr0", "%fr1", "%fr2", "%fr3", "%fr4", "%fr5", "%fr6", "%fr7",
"%fr8", "%fr9", "%fr10", "%fr11", "%fr12", "%fr13", "%fr14", "%fr15",
"%fr16", "%fr17", "%fr18", "%fr19", "%fr20", "%fr21", "%fr22", "%fr23",
"%fr24", "%fr25", "%fr26", "%fr27", "%fr28", "%fr29", "%fr30", "%fr31",
};
// available caller saved registers:
// %r19, %r20, %r21, %r22, %arg3, %arg2, %arg1, %arg0, %ret0, %ret1, %r31
// available callee saved registers:
// %r4, %r5, %r6, %r7, %r8, %r9, %r10, %r11, %r12, %r13, %r14, %r15, %r16, %r17, %r18
PRUint8 registerNumberToColor[] =
{
79, 77, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 78, 11
};
HPPARegisterNumber colorToRegisterNumber[] =
{
// caller saved GR
/*0*/ r19, r20, r21, r22, arg3, arg2, arg1, arg0,
/*8*/ dp, ret0, ret1, r31, rp,
// callee saved GR
/*13*/ r3, r4, r5, r6, r7, r8, r9, r10,
/*21*/ r11, r12, r13, r14, r15, r16, r17, r18,
// caller saved FPR
/*29*/ fr8L, fr8R, fr9L, fr9R, fr10L, fr10R, fr11L, fr11R,
/*37*/ fr22L, fr22R, fr23L, fr23R, fr24L, fr24R, fr25L, fr25R,
/*45*/ fr26L, fr26R, fr27L, fr27R, fr28L, fr28R, fr29L, fr29R,
/*53*/ fr30L, fr30R, fr31L, fr31R,
// callee saved FPR
/*57*/ fr12L, fr12R, fr13L, fr13R, fr14L, fr14R, fr15L, fr15R,
/*65*/ fr16L, fr16R, fr17L, fr17R, fr18L, fr18R, fr19L, fr19R,
/*73*/ fr20L, fr20R, fr21L, fr21R,
// special registers
/*77*/ r1, sp, zero
};
#define COLOR_MASK1(regNum) (1 << registerNumberToColor[regNum])
#define COLOR_MASK2(regNum) (1 << (registerNumberToColor[regNum] - 32))
#define COLOR_MASK3(regNum) (1 << (registerNumberToColor[regNum] - 64))
HPPASpecialCallInfo hscInfo[nSpecialCalls] =
{
{ RemI, "$$remI", 2, 1, 0, 0, COLOR_MASK3(r1), HPPAFuncAddress(HPPAremI) }, // inter with r1
{ RemU, "$$remU", 2, 1, 0, 0, COLOR_MASK3(r1), HPPAFuncAddress(HPPAremU) }, // inter with r1
{ DivI, "$$divI", 2, 1, 0, 0, COLOR_MASK3(r1), HPPAFuncAddress(HPPAdivI) }, // inter with r1
{ DivU, "$$divU", 2, 1, 0, 0, COLOR_MASK3(r1), HPPAFuncAddress(HPPAdivU) }, // inter with r1
};
HPPAInstructionKind shiftAddl[4] =
{
INVALID, SH1ADDL, SH2ADDL, SH3ADDL
};
static inline PRUint32
dis_assemble_3(PRUint32 x)
{
return (((x & 4) >> 2) | ((x & 3) << 1)) & 7;
}
static inline void
dis_assemble_12(PRUint32 as12, PRUint32& x, PRUint32& y)
{
y = (as12 & 0x800) >> 11;
x = ((as12 & 0x3ff) << 1) | ((as12 & 0x400) >> 10);
}
static inline void
dis_assemble_17(PRUint32 as17, PRUint32& x, PRUint32& y, PRUint32& z)
{
z = (as17 & 0x10000) >> 16;
x = (as17 & 0x0f800) >> 11;
y = (((as17 & 0x00400) >> 10) | ((as17 & 0x3ff) << 1)) & 0x7ff;
}
static inline PRUint32
dis_assemble_21 (PRUint32 as21)
{
PRUint32 temp;
temp = (as21 & 0x100000) >> 20;
temp |= (as21 & 0x0ffe00) >> 8;
temp |= (as21 & 0x000180) << 7;
temp |= (as21 & 0x00007c) << 14;
temp |= (as21 & 0x000003) << 12;
return temp;
}
static inline PRUint16
low_sign_unext_14(PRUint16 x)
{
return ((x & 0x1fff) << 1) | ((x & 0x2000) ? 1 : 0);
}
static inline PRUint8
low_sign_unext_5(PRUint8 x)
{
return ((x & 0xf) << 1) | ((x & 0x10) ? 1 : 0);
}
// HPPAInstruction methods
#if defined(DEBUG)
void HPPAInstruction::
printPretty(FILE* f)
{
fprintf(f, "unimp(%s)", hiInfo[kind].string);
}
#endif
HPPARegisterNumber HPPAInstruction::
getR1()
{
InstructionUse* use = getInstructionUseBegin();
InstructionUse* limit = getInstructionUseEnd();
while (use < limit && !use->isVirtualRegister()) use++;
if (use >= limit)
return zero;
else
return udToRegisterNumber(use[0]);
}
HPPARegisterNumber HPPAInstruction::
getR2()
{
InstructionUse* use = getInstructionUseBegin();
InstructionUse* limit = getInstructionUseEnd();
while (use < limit && !use->isVirtualRegister()) use++;
if (use < &limit[-1] && use[1].isVirtualRegister())
use++; // skip R1
if (use >= limit || !use->isVirtualRegister())
return zero;
else
return udToRegisterNumber(use[0]);
}
HPPARegisterNumber HPPAInstruction::
getT()
{
InstructionDefine* def = getInstructionDefineBegin();
InstructionDefine* limit = getInstructionDefineEnd();
while (def < limit && !def->isVirtualRegister()) def++;
if (def >= limit)
return zero;
else
return udToRegisterNumber(def[0]);
}
// HPPAFormat1 methods
// |31 |25 |20 |15 |13 0|
// |-----------------|--------------|--------------|-----|-----------------------------------------|
// | op | b | t/r | s | im14 |
// |-----------------|--------------|--------------|-----|-----------------------------------------|
void HPPAFormat1::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = (hiInfo[kind].opcode << 26) | (getR1() << 21) | (getT() << 16) | low_sign_unext_14(getIm14());
}
#if defined(DEBUG)
void HPPAFormat1::
printPretty(FILE* f)
{
if (flags & HPPA_R1_IS_ZERO)
fprintf(f, "%s %d,%s", hiInfo[kind].string, (PRInt16) getIm14(), getTString());
else
fprintf(f, "%s %d(%s),%s", hiInfo[kind].string, (PRInt16) getIm14(), getR1String(), getTString());
}
#endif
#if defined(DEBUG)
void HPPALoad::
printPretty(FILE* f)
{
fprintf(f, "%s %d(0,%s),%s", hiInfo[kind].string, (PRInt16) getIm14(), getR1String(), getTString());
}
#endif
void HPPAStore::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = (hiInfo[kind].opcode << 26) | (getR1() << 21) | (getR2() << 16) | low_sign_unext_14(getIm14());
}
#if defined(DEBUG)
void HPPAStore::
printPretty(FILE* f)
{
fprintf(f, "%s %s,%d(0,%s)", hiInfo[kind].string, getR2String(), (PRInt16) getIm14(), getR1String());
}
#endif
// HPPAFormat5 methods
// |31 |25 |20 0|
// |-----------------|--------------|--------------------------------------------------------------|
// | op | t/r | im21 |
// |-----------------|--------------|--------------------------------------------------------------|
void HPPAFormat5::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = (hiInfo[kind].opcode << 26) | (getT() << 21) | dis_assemble_21(IM21(im21));
}
#if defined(DEBUG)
void HPPAFormat5::
printPretty(FILE* f)
{
fprintf(f, "%s %d,%s", hiInfo[kind].string, IM21(im21), getTString());
}
#endif
// HPPAFormat6 methods
// |31 |25 |20 |15 |12|11 |5 |4 0|
// |-----------------|--------------|--------------|--------|--|-----------------|--|--------------|
// | op | r2 | r1 | c | f| ext6 |0 | t |
// |-----------------|--------------|--------------|--------|--|-----------------|--|--------------|
void HPPAFormat6::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = (hiInfo[kind].opcode << 26) | (((flags & HPPA_R1_IS_ZERO) ? 0 : getR2()) << 21) | (getR1() << 16) | (hiInfo[kind].ext << 6) | getT();
}
#if defined(DEBUG)
void HPPAFormat6::
printPretty(FILE* f)
{
if (flags & HPPA_IS_COPY)
fprintf(f, "%s %s,%s", hiInfo[kind].string, getR1String(), getTString());
else if (flags & HPPA_R1_IS_ZERO)
fprintf(f, "%s 0,%s,%s", hiInfo[kind].string, getR1String(), getTString());
else
fprintf(f, "%s %s,%s,%s", hiInfo[kind].string, getR1String(), getR2String(), getTString());
}
#endif
// HPPAFormat8 methods
// |31 |25 |20 |15 |12 |9 |4 0|
// |-----------------|--------------|--------------|--------|--------|--------------|--------------|
// | op | r | t | c | ext3 | p | clen |
// |-----------------|--------------|--------------|--------|--------|--------------|--------------|
void HPPAFormat8::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = (hiInfo[kind].opcode << 26) | (getR1() << 21) | (getT() << 16) | (hiInfo[kind].ext << 10) | (cp << 5) | (32 - clen);
}
#if defined(DEBUG)
void HPPAFormat8::
printPretty(FILE* f)
{
fprintf(f, "%s %s,%d,%d,%s", hiInfo[kind].string, getR1String(), cp, clen, getTString());
}
#endif
// HPPAFormat9 methods
// |31 |25 |20 |15 |12 |9 |4 0|
// |-----------------|--------------|--------------|--------|--------|--------------|--------------|
// | op | t | r/im5 | c | ext3 | cp | clen |
// |-----------------|--------------|--------------|--------|--------|--------------|--------------|
void HPPAFormat9::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = (hiInfo[kind].opcode << 26) | (getT() << 21) | ((validIM5(im5) ? low_sign_unext_5(im5) : (PRUint8) getR1()) << 16) |
(hiInfo[kind].ext << 10) | ((31 - cp) << 5) | (32 - clen);
}
#if defined(DEBUG)
void HPPAFormat9::
printPretty(FILE* f)
{
if (validIM5(im5))
fprintf(f, "%s %d,%d,%d,%s", hiInfo[kind].string, IM5(im5), cp, clen, getTString());
else
fprintf(f, "%s %s,%d,%d,%s", hiInfo[kind].string, getR1String(), cp, clen, getTString());
}
#endif
// HPPAFormat11 methods
// |31 |25 |20 |15 |12 | 1| 0|
// |-----------------|--------------|--------------|--------|--------------------------------|--|--|
// | op | r2/p | r1/im5 | c | w1 | n| w|
// |-----------------|--------------|--------------|--------|--------------------------------|--|--|
void HPPAFormat11::
formatToMemory(void* where, uint32 offset)
{
PRUint32 w1, w;
dis_assemble_12((target.getNativeOffset() - (offset + 8)) >> 2, w1, w);
((PRUint32 *)where)[0] = (hiInfo[kind].opcode << 26) | (getR2() << 21) | ((validIM5(im5) ? low_sign_unext_5(im5) : (PRUint8) getR1()) << 16) |
(hcInfo[cond].c << 13) | (w1 << 2) | ((nullification ? 1 : 0) << 1) | w;
if (nullification)
((PRUint32 *)where)[1] = 0x08000240; // nop
}
#if defined(DEBUG)
void HPPAFormat11::
printPretty(FILE* f)
{
if (validIM5(im5))
fprintf(f, "%s,%s%s %d,%s,N%d%s", hiInfo[kind].string, hcInfo[cond].string, nullification ? ",n" : "",
IM5(im5), getR2String(), target.dfsNum, nullification ? "; nop" : "");
else
fprintf(f, "%s,%s%s %s,%s,N%d%s", hiInfo[kind].string, hcInfo[cond].string, nullification ? ",n" : "",
getR1String(), getR2String(), target.dfsNum, nullification ? "; nop" : "");
}
#endif
// HPPAFormat12 methods
// |31 |25 |20 |15 |12 | 1| 0|
// |-----------------|--------------|--------------|--------|--------------------------------|--|--|
// | op | b | w1 | s | w2 | n| w|
// |-----------------|--------------|--------------|--------|--------------------------------|--|--|
void HPPAFormat12::
formatToMemory(void* where, uint32 offset)
{
PRUint32 w2, w1, w;
dis_assemble_17((target.getNativeOffset() - (offset + 8)) >> 2, w1, w2, w);
((PRUint32 *)where)[0] = (hiInfo[kind].opcode << 26) | /*(getT() << 21) |*/ (w1 << 16) | (w2 << 2) | ((nullification ? 1 : 0) << 1) | w;
if (nullification)
((PRUint32 *)where)[1] = 0x08000240; // nop
}
#if defined(DEBUG)
void HPPAFormat12::
printPretty(FILE* f)
{
fprintf(f, "%s%s N%d,%s%s", hiInfo[kind].string, nullification ? ",n" : "",
target.dfsNum, getTString(), nullification ? "; nop" : "");
}
#endif
// HPPAFormat13 methods
// |31 |25 |20 |15 |12 | 1| 0|
// |-----------------|--------------|--------------|--------|--------------------------------|--|--|
// | op | t | w1 | ext3 | w2 | n| w|
// |-----------------|--------------|--------------|--------|--------------------------------|--|--|
void HPPAFormat13::
formatToMemory(void* where, uint32 /*offset*/)
{
PRUint32 w2, w1, w;
dis_assemble_17((((PRUint32) address) - (((PRUint32) where) + 8)) >> 2, w1, w2, w);
((PRUint32 *)where)[0] = (hiInfo[kind].opcode << 26) | (returnRegister << 21) | (w1 << 16) | (w2 << 2) | ((nullification ? 1 : 0) << 1) | w;
if (nullification)
((PRUint32 *)where)[1] = 0x08000240; // nop
}
#if defined(DEBUG)
void HPPAFormat13::
printPretty(FILE* f)
{
fprintf(f, "%s%s %s,%s", hiInfo[kind].string, nullification ? ",n" : "", getAddressString(), getTString());
}
#endif
// HPPAFormat31 methods
// |31 |25 |20 |15 |13|12|11 |9 |8 |5 |4 0|
// |-----------------|--------------|--------------|-----|--|--|-----|--|--------|--|--------------|
// | op | b | im5 | s |a |1 | cc |0 | uid |m | t |
// |-----------------|--------------|--------------|-----|--|--|-----|--|--------|--|--------------|
void HPPAFormat31::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = 0;
}
#if defined(DEBUG)
void HPPAFormat31::
printPretty(FILE* f)
{
fprintf(f, "%s %d(0,%s),%s", hiInfo[kind].string, (PRInt8) getIm5(), getR1String(), getTString());
}
#endif
// HPPAFormat32 methods
// |31 |25 |20 |15 |13|12|11 |9 |8 |5 |4 0|
// |-----------------|--------------|--------------|-----|--|--|-----|--|--------|--|--------------|
// | op | b | im5 | s |a |1 | cc |1 | uid |m | r |
// |-----------------|--------------|--------------|-----|--|--|-----|--|--------|--|--------------|
void HPPAFormat32::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = 0;
}
#if defined(DEBUG)
void HPPAFormat32::
printPretty(FILE* f)
{
fprintf(f, "%s %s,%d(0,%s)", hiInfo[kind].string, getR2String(), (PRInt8) getIm5(), getR1String());
}
#endif
// HPPAFormat40 methods
// |31 |25 |20 |15 |12|11|10 |8 |7 |6 |5 |4 0|
// |-----------------|--------------|--------------|--------|--|--|-----|--|--|--|--|--------------|
// | op | r1 | r2 | sop |r2|f | 3 |x |r1|t |0 | t |
// |-----------------|--------------|--------------|--------|--|--|-----|--|--|--|--|--------------|
void HPPAFormat40::
formatToMemory(void* where, uint32 /*offset*/)
{
*(PRUint32 *)where = 0;
}
#if defined(DEBUG)
void HPPAFormat40::
printPretty(FILE* f)
{
fprintf(f, "%s %s,%s,%s", hiInfo[kind].string, getR1String(), getR2String(), getTString());
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,260 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "prbit.h"
#include "HPPAMul.h"
/*
*-----------------------------------------------------------------------
*
* Local data for an HPPA proc. This should be obtained by asking the
* Code Generator to fill these arrays.
*
*-----------------------------------------------------------------------
*/
static PRInt16 shiftCosts[32] =
{
0, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4
};
static PRInt16 shiftAddCosts[32] =
{
4, 4, 4, 4, 999, 999, 999, 999,
999, 999, 999, 999, 999, 999, 999, 999,
999, 999, 999, 999, 999, 999, 999, 999,
999, 999, 999, 999, 999, 999, 999, 999
};
static PRInt16 shiftSubCosts[32] =
{
4, 999, 999, 999, 999, 999, 999, 999,
999, 999, 999, 999, 999, 999, 999, 999,
999, 999, 999, 999, 999, 999, 999, 999,
999, 999, 999, 999, 999, 999, 999, 999
};
static PRInt16 addCost = 4;
/*
*-----------------------------------------------------------------------
*
* getMulAlgorithm --
*
* Return the best algorithm for an immediate multiplication.
* If algorithm.cost >= maxCost or retval is false then no algorithm
* was found and a regular multiplication should be used.
*
* This algorithm does not work if the register to multiply is larger
* than an PRUint32 and the multiplicand does not fit exactely in an PRUint32.
* e.g.: long long mul by a negative value.
*
*-----------------------------------------------------------------------
*/
bool
getMulAlgorithm(MulAlgorithm* algorithm, PRUint32 multiplicand, PRInt16 maxCost)
{
PRUint32 mask;
PRUint8 currentCost;
PRInt8 shiftBy;
algorithm->cost = maxCost;
if (maxCost <= 0)
return false;
if (multiplicand == 0x1)
{
algorithm->nOperations = 1;
algorithm->cost = 0;
algorithm->operations[0] = maMultiplicand;
return true;
}
if (multiplicand == 0x0)
{
algorithm->nOperations = 1;
algorithm->cost = 0;
algorithm->operations[0] = maZero;
return true;
}
MulAlgorithm* downAlgorithm = new MulAlgorithm();
MulAlgorithm* bestAlgorithm = new MulAlgorithm();
MulAlgorithm* swapAlgorithm;
// we try to do a shift if there is a group of 0 bits.
if ((multiplicand & 0x1) == 0x0)
{
// number of low zero bits.
mask = multiplicand & -multiplicand;
PR_FLOOR_LOG2(shiftBy, mask);
currentCost = shiftCosts[shiftBy];
getMulAlgorithm(downAlgorithm, multiplicand >> shiftBy, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maShiftValue;
maxCost = currentCost;
}
}
// If this is an odd number, we can try to add one or to subtract one.
if ((multiplicand & 0x1) != 0x0)
{
for (mask = 1; (mask & multiplicand) != 0x0; mask <<= 1);
if (mask > 2 && multiplicand != 3)
{
currentCost = addCost;
getMulAlgorithm(downAlgorithm, multiplicand + 1, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = 0;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maSubShiftMultiplicandFromValue;
maxCost = currentCost;
}
}
else
{
currentCost = addCost;
getMulAlgorithm(downAlgorithm, multiplicand - 1, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = 0;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maAddValueToShiftMultiplicand;
maxCost = currentCost;
}
}
}
mask = multiplicand - 1;
PR_FLOOR_LOG2(shiftBy, mask);
while (shiftBy >= 2)
{
PRUint32 d;
d = (0x1 << shiftBy) + 1;
if (multiplicand % d == 0 && multiplicand > d)
{
currentCost = PR_MIN(shiftAddCosts[shiftBy], addCost + shiftCosts[shiftBy]);
getMulAlgorithm(downAlgorithm, multiplicand / d, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maAddValueToShiftValue;
maxCost = currentCost;
}
break;
}
d = (0x1 << shiftBy) - 1;
if (multiplicand % d == 0 && multiplicand > d)
{
currentCost = PR_MIN(shiftSubCosts[shiftBy], addCost + shiftCosts[shiftBy]);
getMulAlgorithm(downAlgorithm, multiplicand / d, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maSubValueFromShiftValue;
maxCost = currentCost;
}
break;
}
shiftBy--;
}
if ((multiplicand & 0x1) != 0x0)
{
mask = multiplicand - 1;
mask = mask & -mask;
if (mask != 0 && (mask & (mask - 1)) == 0)
{
PR_FLOOR_LOG2(shiftBy, mask);
currentCost = shiftAddCosts[shiftBy];
getMulAlgorithm(downAlgorithm, (multiplicand - 1) >> shiftBy, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maAddMultiplicandToShiftValue;
maxCost = currentCost;
}
}
mask = multiplicand + 1;
mask = mask & -mask;
if (mask != 0 && (mask & (mask - 1)) == 0)
{
PR_FLOOR_LOG2(shiftBy, mask);
currentCost = shiftSubCosts[shiftBy];
getMulAlgorithm(downAlgorithm, (multiplicand + 1) >> shiftBy, maxCost - currentCost);
currentCost += downAlgorithm->cost;
if (currentCost < maxCost)
{
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
bestAlgorithm->operations[bestAlgorithm->nOperations] = maSubMultiplicandFromShiftValue;
maxCost = currentCost;
}
}
}
// No algorithm found.
if (maxCost == algorithm->cost)
return false;
// Too long
if (bestAlgorithm->nOperations == 32)
return false;
algorithm->nOperations = bestAlgorithm->nOperations + 1;
algorithm->cost = maxCost;
copy(bestAlgorithm->operations, &bestAlgorithm->operations[algorithm->nOperations], algorithm->operations);
copy(bestAlgorithm->shiftAmount, &bestAlgorithm->shiftAmount[algorithm->nOperations], algorithm->shiftAmount);
// we better find a way to avoid allocating memory each time.
delete downAlgorithm;
delete bestAlgorithm;
return true;
}

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HPPA_MUL_H_
#define _HPPA_MUL_H_
#include "Fundamentals.h"
enum MultiplicationOperation
{
maZero, // total = 0
maMultiplicand, // total = multiplicand
maShiftValue, // total = value << shiftBy
maAddValueToShiftMultiplicand, // total = value + (multiplicand << shiftBy)
maSubShiftMultiplicandFromValue, // total = value - (multiplicand << shiftBy)
maAddValueToShiftValue, // total = (value << shiftBy) + value
maSubValueFromShiftValue, // total = (value << shiftBy) - value
maAddMultiplicandToShiftValue, // total = (value << shiftBy) + multiplicand
maSubMultiplicandFromShiftValue, // total = (value << shiftBy) - multiplicand
};
struct MulAlgorithm
{
PRInt16 cost;
PRUint16 nOperations;
MultiplicationOperation operations[32];
PRUint8 shiftAmount[32];
};
extern bool getMulAlgorithm(MulAlgorithm* algorithm, PRUint32 multiplicand, PRInt16 maxCost);
#endif /* _HPPA_MUL_H_ */

Просмотреть файл

@ -0,0 +1,73 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../../..
MODULE_NAME = hppa
include $(DEPTH)/config/config.mk
INCLUDES += \
-I$(DEPTH)/Utilities/General \
-I$(DEPTH)/Utilities/zlib \
-I$(DEPTH)/Runtime/ClassReader \
-I$(DEPTH)/Compiler/FrontEnd \
-I$(DEPTH)/Runtime/NativeMethods \
-I$(DEPTH)/Runtime/System \
-I$(DEPTH)/Compiler/PrimitiveGraph \
-I$(DEPTH)/Runtime/ClassInfo \
-I$(DEPTH)/Runtime/FileReader \
-I$(DEPTH)/Compiler/CodeGenerator \
-I$(DEPTH)/Compiler/CodeGenerator/md \
-I$(DEPTH)/Compiler/RegisterAllocator \
$(NULL)
CXXSRCS = \
HPPAEmitter.cpp \
HPPAInstruction.cpp \
HPPAMul.cpp \
hppa.nad.burg.cpp \
$(NULL)
include $(DEPTH)/config/rules.mk
export:: hppa.nad.burg.cpp
libs:: $(MODULE)
#
# Rules to generate hppa.nad.burg.[cpp][h]
#
hppa.nad.burg.cpp: hppa.nad.burg $(BURG)
$(BURG) -I -o $@ < $<
hppa.nad.burg: hppa.nad $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations $(DEPTH)/Tools/Nad/nad.pl
$(PERL) $(DEPTH)/Tools/Nad/nad.pl $< $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.h \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.cpp \
$<.burg.h > $@
#
# Extra cleaning
#
clobber::
rm -f hppa.nad.burg.cpp hppa.nad.burg.h hppa.nad.burg
realclean clobber_all::
rm -f hppa.nad.burg.cpp hppa.nad.burg.h hppa.nad.burg

Просмотреть файл

@ -0,0 +1,452 @@
%top
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Burg.h"
%
%terminals
%
%startsymbols
Control
Result
Exception
Store
Vcond
Vint
Vfixed
Vlong
Vfloat
Vdouble
Vptr
Cint
Cfixed
Clong
Cfloat
Cdouble
Cptr
%
%grammar
Vint: coReg_I $1 $
Vlong: coReg_L $1 $
Vfloat: coReg_F $1 $
Vdouble: coReg_D $1 $
Vptr: coReg_A $1 $
Vcond: coReg_C $1 $
Store: coReg_M $1 $
Cint: coReg_I $1 $
Cfixed: coReg_I $1 $
Clong: coReg_L $1 $
Cfloat: coReg_F $1 $
Cdouble: coReg_D $1 $
Cptr: coReg_A $1 $
Vfixed: Vint $1 $
Vint: Vfixed $1 $
Vfixed: poConst_I $1 $emConst_IF
Vint: poConst_I $1 $emConst_I
Vlong: poConst_L $1 $emConst_L
Vfloat: poConst_F $1 $emConst_F
Vdouble: poConst_D $1 $emConst_D
Vptr: poConst_A $1 $emConst_A
Vcond: poConst_C $1 $emConst_C
Store: poBreak(Store) $1 $emBreak
Vint: poArg_I $1 $emArg_I
Vlong: poArg_L $1 $emArg_L
Vfloat: poArg_F $1 $emArg_F
Vdouble: poArg_D $1 $emArg_D
Vptr: poArg_A $1 $emArg_A
Store: poArg_M $1 $emArg_M
Result: poResult_I(Vint) $1 $emResult_I
Result: poResult_L(Vlong) $1 $emResult_L
Result: poResult_F(Vfloat) $1 $emResult_F
Result: poResult_D(Vdouble) $1 $emResult_D
Result: poResult_A(Vptr) $1 $emResult_A
// (not used): poResult_C(Acond) $1 $emResult_C
Result: poResult_M(Store) $1 $emResult_M
Control: poIfLt(Vcond) $1 $emIfLt
Control: poIfEq(Vcond) $1 $emIfEq
Control: poIfLe(Vcond) $1 $emIfLe
Control: poIfGt(Vcond) $1 $emIfGt
Control: poIfLgt(Vcond) $1 $emIfLgt
Control: poIfGe(Vcond) $1 $emIfGe
Control: poIfOrd(Vcond) $1 $emIfOrd
Control: poIfUnord(Vcond) $1 $emIfUnord
Control: poIfULt(Vcond) $1 $emIfULt
Control: poIfUEq(Vcond) $1 $emIfUEq
Control: poIfULe(Vcond) $1 $emIfULe
Control: poIfUGt(Vcond) $1 $emIfUGt
Control: poIfNe(Vcond) $1 $emIfNe
Control: poIfUGe(Vcond) $1 $emIfUGe
Control: poSwitch(Vint) $1 $emSwitch
Vint: poAnd_I(Vint, Vint) $1 $emAnd_I
Vlong: poAnd_L(Vlong, Vlong) $1 $emAnd_L
Vint: poAndI_I(Vint, Cint) $1 $emAndI_I
Vlong: poAndI_L(Vlong, Clong) $1 $emAndI_L
Vint: poOr_I(Vint, Vint) $1 $emOr_I
Vlong: poOr_L(Vlong, Vlong) $1 $emOr_L
Vint: poOrI_I(Vint, Cint) $1 $emOrI_I
Vlong: poOrI_L(Vlong, Clong) $1 $emOrI_L
Vint: poXor_I(Vint, Vint) $1 $emXor_I
Vlong: poXor_L(Vlong, Vlong) $1 $emXor_L
Vint: poXorI_I(Vint, Cint) $1 $emXorI_I
Vlong: poXorI_L(Vlong, Clong) $1 $emXorI_L
Vptr: poAdd_A(Vptr, poShlI_I(Vint, Cint)) $1 $emShAdd_IIndirect
Vint: poAdd_I(Vint, Vint) $1 $emAdd_I
Vlong: poAdd_L(Vlong, Vlong) $1 $emAdd_L
Vptr: poAdd_A(Vptr, Vint) $1 $emAdd_A
Vptr: poAddU_A(Vptr, Vint) $1 $emAddU_A
Vint: poAddI_I(Vint, Cint) $1 $emAddI_I
Vlong: poAddI_L(Vlong, Clong) $1 $emAddI_L
Vptr: poAddI_A(Vptr, Cint) $1 $emAddI_A
Vptr: poAddR_A(Cptr, Vint) $1 $emAddR_A
Vptr: poAddRU_A(Cptr, Vint) $1 $emAddRU_A
Vint: poSub_I(Vint, Vint) $1 $emSub_I
Vlong: poSub_L(Vlong, Vlong) $1 $emSub_L
Vptr: poSub_A(Vptr, Vint) $1 $emSub_A
Vptr: poSubU_A(Vptr, Vint) $1 $emSubU_A
Vint: poSubR_I(Cint, Vint) $1 $emSubR_I
Vlong: poSubR_L(Clong, Vlong) $1 $emSubR_L
Vptr: poSubR_A(Cptr, Vint) $1 $emSubR_A
Vptr: poSubUR_A(Cptr, Vint) $1 $emSubUR_A
Vint: poSubA_I(Vptr, Vptr) $1 $emSubA_I
Vint: poSubAI_I(Vptr, Cptr) $1 $emSubAI_I
Vint: poSubAR_I(Cptr, Vptr) $1 $emSubAR_I
Vfixed: poMul_I(Vfixed, Vfixed) $1 $emMul_I
Vlong: poMul_L(Vlong, Vlong) $1 $emMul_L
Vfixed: poMulI_I(Vfixed, Cfixed) $1 $emMulI_I
Vlong: poMulI_L(Vlong, Clong) $1 $emMulI_L
Vint: poDivI_I(Vint, Cint) $1 $emDivI_I
Vint: poModE_I(Vint, Vint) $1 $emModE_I
Vint: poShl_I(Vint, Vint) $1 $emShl_I
Vlong: poShl_L(Vlong, Vint) $1 $emShl_L
Vint: poShlI_I(Vint, Cint) $1 $emShlI_I
Vlong: poShlI_L(Vlong, Cint) $1 $emShlI_L
Vint: poShlR_I(Cint, Vint) $1 $emShlR_I
Vlong: poShlR_L(Clong, Vint) $1 $emShlR_L
Vint: poShr_I(Vint, Vint) $1 $emShr_I
Vlong: poShr_L(Vlong, Vint) $1 $emShr_L
Vint: poShrI_I(Vint, Cint) $1 $emShrI_I
Vlong: poShrI_L(Vlong, Cint) $1 $emShrI_L
Vint: poShrR_I(Cint, Vint) $1 $emShrR_I
Vlong: poShrR_L(Clong, Vint) $1 $emShrR_L
Vint: poShrU_I(Vint, Vint) $1 $emShrU_I
Vlong: poShrU_L(Vlong, Vint) $1 $emShrU_L
Vint: poShrUI_I(Vint, Cint) $1 $emShrUI_I
Vlong: poShrUI_L(Vlong, Cint) $1 $emShrUI_L
Vint: poShrUR_I(Cint, Vint) $1 $emShrUR_I
Vlong: poShrUR_L(Clong, Vint) $1 $emShrUR_L
Vint: poExt_I(Vint, Cint) $1 $emExt_I
Vlong: poExt_L(Vlong, Cint) $1 $emExt_L
Vfloat: poFAdd_F(Vfloat, Vfloat) $1 $emFAdd_F
Vdouble: poFAdd_D(Vdouble, Vdouble) $1 $emFAdd_D
Vfloat: poFAddI_F(Vfloat, Cfloat) $1 $emFAddI_F
Vdouble: poFAddI_D(Vdouble, Cdouble) $1 $emFAddI_D
Vfloat: poFSub_F(Vfloat, Vfloat) $1 $emFSub_F
Vdouble: poFSub_D(Vdouble, Vdouble) $1 $emFSub_D
Vfloat: poFSubR_F(Cfloat, Vfloat) $1 $emFSubR_F
Vdouble: poFSubR_D(Cdouble, Vdouble) $1 $emFSubR_D
Vfloat: poFMul_F(Vfloat, Vfloat) $1 $emFMul_F
Vdouble: poFMul_D(Vdouble, Vdouble) $1 $emFMul_D
Vfloat: poFMulI_F(Vfloat, Cfloat) $1 $emFMulI_F
Vdouble: poFMulI_D(Vdouble, Cdouble) $1 $emFMulI_D
Vfloat: poFDiv_F(Vfloat, Vfloat) $1 $emFDiv_F
Vdouble: poFDiv_D(Vdouble, Vdouble) $1 $emFDiv_D
Vfloat: poFDivI_F(Vfloat, Cfloat) $1 $emFDivI_F
Vdouble: poFDivI_D(Vdouble, Cdouble) $1 $emFDivI_D
Vfloat: poFDivR_F(Cfloat, Vfloat) $1 $emFDivR_F
Vdouble: poFDivR_D(Cdouble, Vdouble) $1 $emFDivR_D
Vfloat: poFRem_F(Vfloat, Vfloat) $1 $emFRem_F
Vdouble: poFRem_D(Vdouble, Vdouble) $1 $emFRem_D
Vfloat: poFRemI_F(Vfloat, Cfloat) $1 $emFRemI_F
Vdouble: poFRemI_D(Vdouble, Cdouble) $1 $emFRemI_D
Vfloat: poFRemR_F(Cfloat, Vfloat) $1 $emFRemR_F
Vdouble: poFRemR_D(Cdouble, Vdouble) $1 $emFRemR_D
Vint: poConvI_L(Vlong) $1 $emConvI_L
Vlong: poConvL_I(Vint) $1 $emConvL_I
Vint: poFConvI_F(Vfloat) $1 $emFConvI_F
Vint: poFConvI_D(Vdouble) $1 $emFConvI_D
Vlong: poFConvL_F(Vfloat) $1 $emFConvL_F
Vlong: poFConvL_D(Vdouble) $1 $emFConvL_D
Vfloat: poFConvF_I(Vint) $1 $emFConvF_I
Vfloat: poFConvF_L(Vlong) $1 $emFConvF_L
Vfloat: poFConvF_D(Vdouble) $1 $emFConvF_D
Vdouble: poFConvD_I(Vint) $1 $emFConvD_I
Vdouble: poFConvD_L(Vlong) $1 $emFConvD_L
Vdouble: poFConvD_F(Vfloat) $1 $emFConvD_F
Vcond: poCmp_I(Vint, Vint) $1 $emCmp_I
Vcond: poCmp_L(Vlong, Vlong) $1 $emCmp_L
Vcond: poCmpI_I(Vint, Cint) $1 $emCmpI_I
Vcond: poCmpI_L(Vlong, Clong) $1 $emCmpI_L
Vcond: poCmpU_I(Vint, Vint) $1 $emCmpU_I
Vcond: poCmpU_L(Vlong, Vlong) $1 $emCmpU_L
Vcond: poCmpU_A(Vptr, Vptr) $1 $emCmpU_A
Vcond: poCmpUI_I(Vint, Cint) $1 $emCmpUI_I
Vcond: poCmpUI_L(Vlong, Clong) $1 $emCmpUI_L
Vcond: poCmpUI_A(Vptr, Cptr) $1 $emCmpUI_A
Vcond: poFCmp_F(Vfloat, Vfloat) $1 $emFCmp_F
Vcond: poFCmp_D(Vdouble, Vdouble) $1 $emFCmp_D
Vcond: poFCmpI_F(Vfloat, Cfloat) $1 $emFCmpI_F
Vcond: poFCmpI_D(Vdouble, Cdouble) $1 $emFCmpI_D
Vint: poLt_I(Vcond) $1 $emLt_I
Vint: poEq_I(Vcond) $1 $emEq_I
Vint: poLe_I(Vcond) $1 $emLe_I
Vint: poGt_I(Vcond) $1 $emGt_I
Vint: poLgt_I(Vcond) $1 $emLgt_I
Vint: poGe_I(Vcond) $1 $emGe_I
Vint: poOrd_I(Vcond) $1 $emOrd_I
Vint: poUnord_I(Vcond) $1 $emUnord_I
Vint: poULt_I(Vcond) $1 $emULt_I
Vint: poUEq_I(Vcond) $1 $emUEq_I
Vint: poULe_I(Vcond) $1 $emULe_I
Vint: poUGt_I(Vcond) $1 $emUGt_I
Vint: poNe_I(Vcond) $1 $emNe_I
Vint: poUGe_I(Vcond) $1 $emUGe_I
Vint: poCatL_I(Vcond) $1 $emCatL_I
Vint: poCatG_I(Vcond) $1 $emCatG_I
Vint: poCatCL_I(Vcond) $1 $emCatCL_I
Vint: poCatCG_I(Vcond) $1 $emCatCG_I
Exception: poChkNull(Vptr) $1 $emChkNull
Exception: poLimit(Vint, Vint) $1 $emLimit
Exception: poLimitI(Vint, Cint) $1 $emLimitI
Exception: poLimitR(Cint, Vint) $1 $emLimitR
Vint: poLd_I(Vptr) $1 $emLd_I
Vlong: poLd_L(Vptr) $1 $emLd_L
Vfloat: poLd_F(Vptr) $1 $emLd_F
Vdouble: poLd_D(Vptr) $1 $emLd_D
Vptr: poLd_A(Vptr) $1 $emLd_A
Vint: poLdE_I(Cptr) $1 $emLdE_I
Vlong: poLdE_L(Cptr) $1 $emLdE_L
Vfloat: poLdE_F(Cptr) $1 $emLdE_F
Vdouble: poLdE_D(Cptr) $1 $emLdE_D
Vptr: poLdE_A(Cptr) $1 $emLdE_A
Vint: poLdG_I(Cptr) $1 $emLdG_I
Vlong: poLdG_L(Cptr) $1 $emLdG_L
Vfloat: poLdG_F(Cptr) $1 $emLdG_F
Vdouble: poLdG_D(Cptr) $1 $emLdG_D
Vptr: poLdG_A(Cptr) $1 $emLdG_A
Vint: poLdS_B(Vptr) $1 $emLdS_B
Vint: poLdS_H(Vptr) $1 $emLdS_H
Vint: poLdSE_B(Cptr) $1 $emLdSE_B
Vint: poLdSE_H(Cptr) $1 $emLdSE_H
Vint: poLdSG_B(Cptr) $1 $emLdSG_B
Vint: poLdSG_H(Cptr) $1 $emLdSG_H
Vint: poLdU_B(Vptr) $1 $emLdU_B
Vint: poLdU_H(Vptr) $1 $emLdU_H
Vint: poLdUE_B(Cptr) $1 $emLdUE_B
Vint: poLdUE_H(Cptr) $1 $emLdUE_H
Vint: poLdUG_B(Cptr) $1 $emLdUG_B
Vint: poLdUG_H(Cptr) $1 $emLdUG_H
Vint: poLdV_I(Vptr) $1 $emLdV_I
Vlong: poLdV_L(Vptr) $1 $emLdV_L
Vfloat: poLdV_F(Vptr) $1 $emLdV_F
Vdouble: poLdV_D(Vptr) $1 $emLdV_D
Vptr: poLdV_A(Vptr) $1 $emLdV_A
Vint: poLdVE_I(Cptr) $1 $emLdVE_I
Vlong: poLdVE_L(Cptr) $1 $emLdVE_L
Vfloat: poLdVE_F(Cptr) $1 $emLdVE_F
Vdouble: poLdVE_D(Cptr) $1 $emLdVE_D
Vptr: poLdVE_A(Cptr) $1 $emLdVE_A
Vint: poLdVG_I(Cptr) $1 $emLdVG_I
Vlong: poLdVG_L(Cptr) $1 $emLdVG_L
Vfloat: poLdVG_F(Cptr) $1 $emLdVG_F
Vdouble: poLdVG_D(Cptr) $1 $emLdVG_D
Vptr: poLdVG_A(Cptr) $1 $emLdVG_A
Vint: poLdVS_B(Vptr) $1 $emLdVS_B
Vint: poLdVS_H(Vptr) $1 $emLdVS_H
Vint: poLdVSE_B(Cptr) $1 $emLdVSE_B
Vint: poLdVSE_H(Cptr) $1 $emLdVSE_H
Vint: poLdVSG_B(Cptr) $1 $emLdVSG_B
Vint: poLdVSG_H(Cptr) $1 $emLdVSG_H
Vint: poLdVU_B(Vptr) $1 $emLdVU_B
Vint: poLdVU_H(Vptr) $1 $emLdVU_H
Vint: poLdVUE_B(Cptr) $1 $emLdVUE_B
Vint: poLdVUE_H(Cptr) $1 $emLdVUE_H
Vint: poLdVUG_B(Cptr) $1 $emLdVUG_B
Vint: poLdVUG_H(Cptr) $1 $emLdVUG_H
Vint: poLdC_I(Vptr) $1 $emLdC_I
Vint: poLdC_L(Vptr) $1 $emLdC_L
Vint: poLdC_F(Vptr) $1 $emLdC_F
Vint: poLdC_D(Vptr) $1 $emLdC_D
Vint: poLdC_A(Vptr) $1 $emLdC_A
Vint: poLdCE_I(Vptr) $1 $emLdCE_I
Vint: poLdCE_L(Vptr) $1 $emLdCE_L
Vint: poLdCE_F(Vptr) $1 $emLdCE_F
Vint: poLdCE_D(Vptr) $1 $emLdCE_D
Vint: poLdCE_A(Vptr) $1 $emLdCE_A
Vint: poLdC_I(poAddI_A(Vptr, Cint)) $0 $emLdC_IRegisterIndirect
Vint: poLd_I(poAddI_A(Vptr, Cint)) $0 $emLd_IRegisterIndirect
// poLdCG_I = 257, // Load constant global *Cptr -> Vint (not used)
// poLdCG_L = 258, // Load constant global *Cptr -> Vlong (not used)
// poLdCG_F = 259, // Load constant global *Cptr -> Vfloat (not used)
// poLdCG_D = 260, // Load constant global *Cptr -> Vdouble (not used)
// poLdCG_A = 261, // Load constant global *Cptr -> Vptr (not used)
Vint: poLdCS_B(Vptr) $1 $emLdCS_B
Vint: poLdCS_H(Vptr) $1 $emLdCS_H
Vint: poLdCSE_B(Cptr) $1 $emLdCSE_B
Vint: poLdCSE_H(Cptr) $1 $emLdCSE_H
//Vint (not used): poLdCSG_B(Cptr) $1 $emLdCSG_B
//Vint (not used): poLdCSG_H(Cptr) $1 $emLdCSG_H
Vint: poLdCU_B(Vptr) $1 $emLdCU_B
Vint: poLdCU_H(Vptr) $1 $emLdCU_H
Vint: poLdCUE_B(Cptr) $1 $emLdCUE_B
Vint: poLdCUE_H(Cptr) $1 $emLdCUE_H
//Vint (not used): poLdCUG_B(Cptr) $1 $emLdCUG_B
//Vint (not used): poLdCUG_H(Cptr) $1 $emLdCUG_H
Store: poSt_B(Vptr, Vint) $1 $emSt_B
Store: poSt_H(Vptr, Vint) $1 $emSt_H
Store: poSt_I(Vptr, Vint) $1 $emSt_I
Store: poSt_L(Vptr, Vlong) $1 $emSt_L
Store: poSt_F(Vptr, Vfloat) $1 $emSt_F
Store: poSt_D(Vptr, Vdouble) $1 $emSt_D
Store: poSt_A(Vptr, Vptr) $1 $emSt_A
Store: poStI_B(Vptr, Cint) $1 $emStI_B
Store: poStI_H(Vptr, Cint) $1 $emStI_H
Store: poStI_I(Vptr, Cint) $1 $emStI_I
Store: poStI_L(Vptr, Clong) $1 $emStI_L
Store: poStI_F(Vptr, Cfloat) $1 $emStI_F
Store: poStI_D(Vptr, Cdouble) $1 $emStI_D
Store: poStI_A(Vptr, Cptr) $1 $emStI_A
Store: poStE_B(Cptr, Vint) $1 $emStE_B
Store: poStE_H(Cptr, Vint) $1 $emStE_H
Store: poStE_I(Cptr, Vint) $1 $emStE_I
Store: poStE_L(Cptr, Vlong) $1 $emStE_L
Store: poStE_F(Cptr, Vfloat) $1 $emStE_F
Store: poStE_D(Cptr, Vdouble) $1 $emStE_D
Store: poStE_A(Cptr, Vptr) $1 $emStE_A
Store: poStEI_B(Cptr, Cint) $1 $emStEI_B
Store: poStEI_H(Cptr, Cint) $1 $emStEI_H
Store: poStEI_I(Cptr, Cint) $1 $emStEI_I
Store: poStEI_L(Cptr, Clong) $1 $emStEI_L
Store: poStEI_F(Cptr, Cfloat) $1 $emStEI_F
Store: poStEI_D(Cptr, Cdouble) $1 $emStEI_D
Store: poStEI_A(Cptr, Cptr) $1 $emStEI_A
Store: poStG_B(Cptr, Vint) $1 $emStG_B
Store: poStG_H(Cptr, Vint) $1 $emStG_H
Store: poStG_I(Cptr, Vint) $1 $emStG_I
Store: poStG_L(Cptr, Vlong) $1 $emStG_L
Store: poStG_F(Cptr, Vfloat) $1 $emStG_F
Store: poStG_D(Cptr, Vdouble) $1 $emStG_D
Store: poStG_A(Cptr, Vptr) $1 $emStG_A
Store: poStGI_B(Cptr, Cint) $1 $emStGI_B
Store: poStGI_H(Cptr, Cint) $1 $emStGI_H
Store: poStGI_I(Cptr, Cint) $1 $emStGI_I
Store: poStGI_L(Cptr, Clong) $1 $emStGI_L
Store: poStGI_F(Cptr, Cfloat) $1 $emStGI_F
Store: poStGI_D(Cptr, Cdouble) $1 $emStGI_D
Store: poStGI_A(Cptr, Cptr) $1 $emStGI_A
Store: poStV_B(Vptr, Vint) $1 $emStV_B
Store: poStV_H(Vptr, Vint) $1 $emStV_H
Store: poStV_I(Vptr, Vint) $1 $emStV_I
Store: poStV_L(Vptr, Vlong) $1 $emStV_L
Store: poStV_F(Vptr, Vfloat) $1 $emStV_F
Store: poStV_D(Vptr, Vdouble) $1 $emStV_D
Store: poStV_A(Vptr, Vptr) $1 $emStV_A
Store: poStVI_B(Vptr, Cint) $1 $emStVI_B
Store: poStVI_H(Vptr, Cint) $1 $emStVI_H
Store: poStVI_I(Vptr, Cint) $1 $emStVI_I
Store: poStVI_L(Vptr, Clong) $1 $emStVI_L
Store: poStVI_F(Vptr, Cfloat) $1 $emStVI_F
Store: poStVI_D(Vptr, Cdouble) $1 $emStVI_D
Store: poStVI_A(Vptr, Cptr) $1 $emStVI_A
Store: poStVE_B(Cptr, Vint) $1 $emStVE_B
Store: poStVE_H(Cptr, Vint) $1 $emStVE_H
Store: poStVE_I(Cptr, Vint) $1 $emStVE_I
Store: poStVE_L(Cptr, Vlong) $1 $emStVE_L
Store: poStVE_F(Cptr, Vfloat) $1 $emStVE_F
Store: poStVE_D(Cptr, Vdouble) $1 $emStVE_D
Store: poStVE_A(Cptr, Vptr) $1 $emStVE_A
Store: poStVEI_B(Cptr, Cint) $1 $emStVEI_B
Store: poStVEI_H(Cptr, Cint) $1 $emStVEI_H
Store: poStVEI_I(Cptr, Cint) $1 $emStVEI_I
Store: poStVEI_L(Cptr, Clong) $1 $emStVEI_L
Store: poStVEI_F(Cptr, Cfloat) $1 $emStVEI_F
Store: poStVEI_D(Cptr, Cdouble) $1 $emStVEI_D
Store: poStVEI_A(Cptr, Cptr) $1 $emStVEI_A
Store: poStVG_B(Cptr, Vint) $1 $emStVG_B
Store: poStVG_H(Cptr, Vint) $1 $emStVG_H
Store: poStVG_I(Cptr, Vint) $1 $emStVG_I
Store: poStVG_L(Cptr, Vlong) $1 $emStVG_L
Store: poStVG_F(Cptr, Vfloat) $1 $emStVG_F
Store: poStVG_D(Cptr, Vdouble) $1 $emStVG_D
Store: poStVG_A(Cptr, Vptr) $1 $emStVG_A
Store: poStVGI_B(Cptr, Cint) $1 $emStVGI_B
Store: poStVGI_H(Cptr, Cint) $1 $emStVGI_H
Store: poStVGI_I(Cptr, Cint) $1 $emStVGI_I
Store: poStVGI_L(Cptr, Clong) $1 $emStVGI_L
Store: poStVGI_F(Cptr, Cfloat) $1 $emStVGI_F
Store: poStVGI_D(Cptr, Cdouble) $1 $emStVGI_D
Store: poStVGI_A(Cptr, Cptr) $1 $emStVGI_A
Store: poSt_I(poAddI_A(Vptr, Cint), Vint) $0 $emSt_IRegisterIndirect
Store: poStI_I(poAddI_A(Vptr, Cint), Cint) $0 $emStI_IRegisterIndirect
// Store, Vint: poMEnter_A(Vptr) $1 $emMEnter_A
// Store, Vint: poMEnterG_A(Cptr) $1 $emMEnterG_A
// Store, Vint: poMExit_A(Vptr) $1 $emMExit_A
// Store, Vint: poMExitG_A(Cptr) $1 $emMExitG_A
// Vptr: poLookupV_A(Vptr, Cint) $1 $emLookupV_A
// Vptr: poLookupI_A(Vptr, Cint) $1 $emLookupI_A
// ...: poSysCall(M) $1 $emSysCall
// Store, ...: poSysCallV(M) $1 $emSysCallV
// ..., E: poSysCallE(M) $1 $emSysCallE
// Store, ..., E: poSysCallEV(M) $1 $emSysCallEV
//Store, ..., E: poCall(Va) $1 $emCall
VInt: poCallI $1 $emCallI_I
Vlong: poCallI $1 $emCallI_L
Vfloat: poCallI $1 $emCallI_F
Vdouble: poCallI $1 $emCallI_D
Vptr: poCallI $1 $emCallI_P
// Store, ..., E: poCallF(F) $1 $emCallF
%

Просмотреть файл

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// AssembledInstructions.h
#ifndef _H_ASSEMBLEDINSTRUCTIONS
#define _H_ASSEMBLEDINSTRUCTIONS
const Uint32 kBlr = 0x4e800020; // blr
const Uint32 kBlrl = 0x4e800021; // blrl
const Uint32 kMtlrR0 = 0x7c0803a6; // mtlr r0
const Uint32 kMtctrR0 = 0x7c0903a6; // mtctr r0
const Uint32 kBctr = 0x4e800420; // bctr
const Uint32 kOriR0 = 0x60000000; // ori r0, r0, 0
const Uint32 kAddiR0 = 0x38000000; // addi r0, r0, 0
const Uint32 addisR0 = 0x3C000000; // addis r0, r0, 0
const Uint32 kBla = 0x48000003; // bla
const Uint32 kBl = 0x48000001; // bl
const Uint32 kB = 0x48000000; // b
const Uint32 kNop = 0x60000000; // nop
const Uint32 kLwzR0_R13 = 0x800D0000; // lwz r0, ?(r13)
inline Uint32
shiftLeftMask(Uint32 inValue, Uint32 inShift, Uint32 inMask = 0xFFFFFFFF)
{
return ((inValue << inShift) & inMask);
}
inline Uint32
makeDForm(Uint8 inOpcd, Uint8 inD, Uint8 inA, Int16 inIMM)
{
return (shiftLeftMask(inOpcd, 26) |
shiftLeftMask(inD, 21) |
shiftLeftMask(inA, 16) |
shiftLeftMask(inIMM, 0, 0xFFFF));
}
const uint32 mfcrR0 = 0x7c000026; // mfcr r0
const uint32 stwR04R1 = 0x90010004; // stw r0, 4(r1)
const uint32 mflrR0 = 0x7c0802a6; // mflr r0
const uint32 stwR08R1 = 0x90010008; // stw r0, 8(r1)
const uint32 stfd_FR_offR1 = 0xd8010000; // stfd fr?, ?(r1)
const uint32 stw_R_offR1 = 0x90010000; // stw r?, ?(r1)
const uint32 stwuR1_offR1 = 0x94210000; // stwu r1, ?(r1)
const uint32 lisR12_imm = 0x3d800000; // lis r12, ?
const uint32 oriR12R12_imm = 0x618c0000; // ori r12, r12, ?
const uint32 stwuxR1R1R12 = 0x7c21616e; // stwux r1, r1, r12
const uint32 lwzR08R1 = 0x80010008; // lwz r0, 8(r1)
const uint32 lwzR04R1 = 0x80010004; // lwz r0, 4(r1)
const uint32 mtcrR0 = 0x7c0ff120; // mtcr r0
const uint32 lfd_FR_offR1 = 0xc8010000; // lfd fr?, ?(r1)
const uint32 lwz_R_offR1 = 0x80010000; // lwz r?, ?(r1)
const uint32 addiR1R1_imm = 0x38210000; // addi r1, r1, ?
const uint32 addR1R1R12 = 0x7c216214; // add r1, r1, r12
#endif //_H_ASSEMBLEDINSTRUCTIONS

Просмотреть файл

@ -0,0 +1,92 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ../../../..
CPPSRCS = PPC601AppleMacOSEmitter.cpp \
PPCInstructions.cpp \
ppc601-macos.nad.burg.cpp \
$(NULL)
LOCAL_MD_EXPORTS_ppc = AssembledInstructions.h \
PPC601AppleMacOSEmitter.h \
PPC601AppleMacOS_Support.h \
PPC601Cpu.h \
PPCCalls.h \
PPCInstructionTemplates.h \
PPCInstructions.h \
$(NULL)
MODULE_NAME = EF
#######################################################################
# (2) Include "component" configuration information. #
#######################################################################
include $(DEPTH)/config/config.mk
#######################################################################
# (3) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#######################################################################
# (4) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
#
# Rules to obtain burg-generated files
#
export:: ppc601-macos.nad.burg.cpp
#
# Rules to generate ppc601-macos.nad.burg.[cpp][h]
#
ppc601-macos.nad.burg.cpp: ppc601-macos.nad.burg $(BURG)
$(BURG) -I -o $@ < $<
ppc601-macos.nad.burg: ppc601-macos.nad $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations $(DEPTH)/Tools/Nad/nad.pl
$(PERL) $(DEPTH)/Tools/Nad/nad.pl $< $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.h \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.cpp \
$<.burg.h > $@
#
# Extra cleaning
#
clobber::
rm -f ppc601-macos.nad.burg.cpp ppc601-macos.nad.burg.h ppc601-macos.nad.burg
realclean clobber_all::
rm -f ppc601-macos.nad.burg.cpp ppc601-macos.nad.burg.h ppc601-macos.nad.burg

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,190 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// PPC601AllMacOSEmitter.h
//
// Scott M. Silver
//
#ifndef _H_PPC601AllMacOSEmitter
#define _H_PPC601AllMacOSEmitter
#include "InstructionEmitter.h"
#include "VirtualRegister.h"
#include "Value.h"
#include "PPCInstructions.h"
#include "PPC601AppleMacOS_Support.h"
#include "FormatStructures.h" // for FCI, StackFrameInfo
/* FIX these have been moved to FormatStructures.h
struct StackFrameInfo
{
Uint8 GPR_words;
Uint8 FPR_words;
Uint32 localStore_bytes;
// returns the offset into the stack frame of the beginning of the restore area
Uint32 getRestoreOffset() { return localStore_bytes; }
};
// struct FormattedCodeInfo;
*/
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic> class Call;
class PPCEmitter :
public InstructionEmitter
{
// these Call Instructions set "themselves" up, ie they call "useProducer"
friend class Call<true, true, false, false>;
friend class Call<true, false, false, false>;
friend class Call<false, false, false, false>;
friend class Call<true, true, true, false>;
friend class Call<true, true, true, true>;
friend class MacDebugger;
friend class PPCFormatter; // uses protected member variables for linkage, etc
protected:
uint32 mMaxArgWords; // maximum words needed in call build area (accumulated)
uint32 mCrossTOCPtrGlCount; // number of ptr glue's needed (all are cross-toc now, even if not needed)
JitGlobals mAccumulatorTOC; // TOC which contains all the data extracted at emit time, transferred to actual TOC
// when formatting (we need to make sure we have a TOC which can contain all of the
// necessary data)
public:
PPCEmitter(Pool& inPool, VirtualRegisterManager& inVrManager) :
InstructionEmitter(inPool, inVrManager),
mCrossTOCPtrGlCount(0),
mMaxArgWords(0) { }
virtual void emitPrimitive(Primitive& inPrimitive, NamedRule inRule);
bool emitCopyAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& fromVr, VirtualRegister& toVr);
void emitLoadAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& loadedReg, VirtualRegister& stackReg);
void emitStoreAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& storedReg, VirtualRegister& stackReg);
Instruction& emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget);
void emitArguments(ControlNode::BeginExtra& inBeginNode);
private:
void emit_LimitR(Primitive& inPrimitive);
void emit_Limit(Primitive& inPrimitive, PPCInsnFlags inFlags);
void emit_Const_I(Primitive& inPrimitive);
void emit_Const_F(Primitive& inPrimitive);
void emit_Ld_IRegisterIndirect(Primitive& inPrimitive);
void emit_Add_I(Primitive& inPrimitive);
void emit_AddI_I(Primitive& inPrimitive);
void emit_Div_I(Primitive& inPrimitive);
void emit_DivE_I(Primitive& inPrimitive);
void emit_DivI_I(Primitive& inPrimitive);
void emit_DivR_I(Primitive& inPrimitive);
void emit_DivRE_I(Primitive& inPrimitive);
void emit_DivU_I(Primitive& inPrimitive);
void emit_DivUE_I(Primitive& inPrimitive);
void emit_DivUI_I(Primitive& inPrimitive);
void emit_DivUR_I(Primitive& inPrimitive);
void emit_DivURE_I(Primitive& inPrimitive);
void emit_Mod_I(Primitive& inPrimitive);
void emit_ModE_I(Primitive& inPrimitive);
void emit_CmpI_I(Primitive& inPrimitive);
void emit_Cmp_I(Primitive& inPrimitive);
void emit_StI_I(Primitive& inPrimitive);
void emit_StI_IRegisterIndirect(Primitive& inPrimitive);
void emit_St_IRegisterIndirect(Primitive& inPrimitive);
void emit_ShlI_I(Primitive& inPrimitive);
void emit_Call(Primitive& inPrimitive);
void emit_Result_I(Primitive& inPrimitive);
void emit_Result_F(Primitive& inPrimitive);
void genBranch(Primitive& inPrimitive, Condition2 cond);
void genLoadIZero(Primitive& inPrimitive, PPCInsnFlags inFlags);
void genArith_ID(Primitive& inPrimitive, DFormKind inKind, XFormKind inXKind);
void genArith_IX(Primitive& inPrimitive, XFormKind inKind);
void genArith_RD(Primitive& inPrimitive, DFormKind inKind, XFormKind inXKind, bool inIsUnsigned);
void genArithReversed_IX(Primitive& inPrimitive, XFormKind inKind);
void emit_SubR(Primitive& inPrimitive, bool inUnsigned);
void emit_SubI(Primitive& inPrimitive);
void genThrowIfDivisorZero(Primitive& inPrimitive);
protected:
VirtualRegister& genLoadConstant_I(DataNode& inPrimitive, Int32 inConstant);
VirtualRegister& genLoadConstant_F(DataNode& inPrimitive, Flt32 inConstant);
};
class PPCFormatter
{
private:
StackFrameInfo mStackPolicy;
protected:
void* mNextFreePostMethod; // next free block of memory following the method's epilog (valid after beginFormatting)
JitGlobals* mRealTOC; // contains this methods actual TOC (valid after beginFormatting)
Int16 mRealTOCOffset; // this is the "fix-up" added to an offset obtained from the accumulator TOC (valid after beginFormatting)
uint8 mSaveGPRwords; // number of non-volatile GPR's used in the function (valid after calculatePrologEpilog)
uint8 mSaveFPRwords; // number of non-volatile FPR's used in the function (valid after calculatePrologEpilog)
uint32 mFrameSizeWords; // whole size of frame (valid after calculatePrologEpilog)
// these Instructions need access to mNextFreePostMethod and the real TOC
friend class Call<true, true, false, false>;
friend class Call<true, false, false, false>;
friend class Call<false, false, false, false>;
friend class Call<true, true, true, false>;
friend class Call<true, true, true, true>;
friend class MacDebugger;
// Fix-up for real TOC
friend class LdD_RTOC;
public:
const PPCEmitter& mEmitter;
PPCFormatter(const MdEmitter& inEmitter) :
mEmitter(inEmitter) { }
void calculatePrologEpilog(Method& inMethod, Uint32& outPrologSize, Uint32& outEpilogSize);
void formatEpilogToMemory(void* inWhere);
void formatPrologToMemory(void* inWhere);
void beginFormatting(const FormattedCodeInfo& inInfo);
void endFormatting(const FormattedCodeInfo& /*inInfo*/) { }
void calculatePrePostMethod(Method& inMethod, Uint32& outPreMethodSize, Uint32& outPostMethodSize);
void formatPostMethodToMemory(void* inWhere, const FormattedCodeInfo& inInfo);
void formatPreMethodToMemory(void* /*inWhere*/, const FormattedCodeInfo& /*inInfo*/) { }
void initStackFrameInfo() {}
Uint8* createTransitionVector(const FormattedCodeInfo& /*inInfo*/);
StackFrameInfo& getStackFrameInfo() {return mStackPolicy; }
};
#ifdef DEBUG
void *disassemble1(LogModuleObject &f, void* inFrom);
#endif
#endif // _H_PPC601AllMacOSEmitter

Просмотреть файл

@ -0,0 +1,471 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// PPC601AppleMacOS_Support.cpp.
//
// Scott M. Silver
//
// Support for the "Just-In-Time" part of the compiler
// Also a handful of routines for dealing with PowerPC linkage oddities (ptr gl, etc)
#include "NativeCodeCache.h"
#include "NativeFormatter.h"
#include "PPC601AppleMacOS_Support.h"
#include "NativeFormatter.h"
#include "AssembledInstructions.h"
#include "JavaObject.h"
// All volatile registers
struct VolatileRegisters
{
Uint32 r3; Uint32 r4; Uint32 r5; Uint32 r6;
Uint32 r7; Uint32 r8; Uint32 r9; Uint32 r10;
Flt64 fp0; Flt64 fp1; Flt64 fp2; Flt64 fp3;
Flt64 fp4; Flt64 fp5; Flt64 fp6; Flt64 fp7;
Flt64 fp8; Flt64 fp9; Flt64 fp10; Flt64 fp11;
Flt64 fp12; Flt64 fp13; Flt64 r31;
};
static void*
formatDynamicPtrGl(void* inStart, uint8 inRegister);
static void
formatCompileStubPtrGl(void* inStart);
asm static void
locate();
asm void
saveVolatiles(VolatileRegisters *vr);
asm void
restoreVolatiles(VolatileRegisters *vr);
const uint32 kDynamicPtrGlBytes = 20; // see formatDynamicPtrGl
// formatDynamicPtrGl
//
// Output some pointer glue through register inRegister
// beginning at inStart in memory. We require that
// the size of the buffer be at least kDynamicPtrGlBytes
// long. This kind of pointer glue is used for
// dispatching v-table based (dynamic) calls.
static void*
formatDynamicPtrGl(void* inStart, Uint8 inRegister)
{
Uint32* curPC = (Uint32*) inStart;
*curPC++ = makeDForm(36, 2, 1, 20); // stw rtoc, 20(sp)
*curPC++ = makeDForm(32, 0, inRegister, 0); // lwz r0, 0(inRegister)
*curPC++ = makeDForm(32, 2, inRegister, 4); // lwz rtoc, 4(inRegister);
*curPC++ = kMtctrR0; // mtctr r0
*curPC++ = kBctr; // bctr
return (curPC);
}
// formatCrossTocPtrGl
//
// Output cross-toc ptr gl beginning at inStart.
// Use inTOCOffset at the offset in the TOC to find
// the callee's TVector ptr. The buffer beginning at inStart
// must be at least kCrossTocPtrGlBytes long.
void*
formatCrossTocPtrGl(void* inStart, int16 inTOCOffset)
{
uint32* curPC = (uint32*) inStart;
*curPC++ = makeDForm(32, 12, 2, inTOCOffset); // lwz r12, offset(rtoc)
*curPC++ = makeDForm(36, 2, 1, 20); // stw rtoc, 20(sp)
*curPC++ = makeDForm(32, 0, 12, 0); // lwz r0, 0(r12)
*curPC++ = makeDForm(32, 2, 12, 4); // lwz rtoc, 4(r12);
*curPC++ = kMtctrR0; // mtctr r0
*curPC++ = kBctr; // bctr
return (curPC);
}
const uint32 kCompileStubPtrGlBytes = 12; // see formatCompileStubPtrGl
// formatCompileStubPtrGl
//
// Output a short stub beginng at inStart which loads
// the address of "locate" and jumps to it. The TOC must be set to
// the system's TOC before this routine is called (which is why a compile stub
// has a TVector with it's TOC set to the system TOC). inStart is
// assumbed to be a buffer of atleast kCompileStubPtrGlBytes.
static void
formatCompileStubPtrGl(void* inStart)
{
uint32* curPC = (uint32*) inStart;
// this is some cruft to locate the offset (from C) to locate's TVector
uint8* startTOC = ((uint8**) formatCompileStubPtrGl)[1]; // grab our TOC
uint8* compileStubFunction = (uint8*) locate; // grab &locate (which is ptr to TVector)
*curPC++ = makeDForm(32, 0, 2, compileStubFunction - startTOC); // lwz r0, locate(RTOC)
*curPC++ = kMtctrR0; // mtctr r0
*curPC++ = kBctr; // bctr
}
// DynamicPtrGlManager
//
// Manages a hunk of dynamic ptr gl
// FIX-ME synchronization
class DynamicPtrGlManager
{
public:
enum
{
kFirstPossibleRegister = 4, // since r3 must be the this ptr and can never be used for dynamic dispatching
kLastPossibleRegister = 31,
kTotalPtrGls = kLastPossibleRegister - kFirstPossibleRegister + 1
};
DynamicPtrGlManager()
{
void* allPtrGls = NativeCodeCache::getCache().acquireMemory(kTotalPtrGls * kDynamicPtrGlBytes);
mPtrGl = new void*[kTotalPtrGls];
void** curPtrGl = mPtrGl;
for (int curReg = kFirstPossibleRegister; curReg < kLastPossibleRegister + 1; curReg++)
{
*curPtrGl++ = allPtrGls;
allPtrGls = formatDynamicPtrGl(allPtrGls, curReg);
}
}
void *
getGl(void* DEBUG_ONLY(inFromWhere), Uint8 inWhichRegister)
{
#ifdef DEBUG
Int32 dummy;
#endif
assert(inWhichRegister >= kFirstPossibleRegister && inWhichRegister <= kLastPossibleRegister);
// FIX-ME allocate new ptr glues if this fails
assert(canBePCRelative(inFromWhere, mPtrGl[inWhichRegister - kFirstPossibleRegister], dummy));
return (mPtrGl[inWhichRegister - kFirstPossibleRegister]);
}
void** mPtrGl;
};
DynamicPtrGlManager sPtrGlueManager;
void* getDynamicPtrGl(void* inFromWhere, Uint8 inWhichRegister)
{
return (sPtrGlueManager.getGl(inFromWhere, inWhichRegister));
}
// getCompileStubPtrGl
//
// Locate a compile stub ptr gl withing pc-relative range of inFromWhere
// If one does not exist, create one. Assume that the newly created
// one will be in range. We also assume we will be reusing this often
// due to (hopefully) monotonically increasing addresses of new blocks
// of memory. FIX-ME?
//
// sMostRecentCompileStubPtrGl is maintained such that it is a single
// entry cache for the last CompileStubPtrGl we generated.
//
// A compileStubPtrGl is a sequence of instructions which jumps to
// the "locate" function which, in some way, locates/compiles/loads, etc
// a currently uncompiled method.
void* getCompileStubPtrGl(void* inFromWhere)
{
Int32 dummyOffset;
static void* sMostRecentCompileStubPtrGl = NULL; // This is a global!
// make a new ptr glue for the compile stub
if ((sMostRecentCompileStubPtrGl == NULL) || (!canBePCRelative(inFromWhere, sMostRecentCompileStubPtrGl, dummyOffset)))
{
void* newPtrGl = NativeCodeCache::getCache().acquireMemory(kCompileStubPtrGlBytes);
formatCompileStubPtrGl(newPtrGl);
sMostRecentCompileStubPtrGl = newPtrGl;
}
// assert that we actually succeeded in our goal, this really
// should result in programattic failure (abort, etc)
bool compileStubAssertion = canBePCRelative(inFromWhere, sMostRecentCompileStubPtrGl, dummyOffset);
assert(compileStubAssertion);
return (sMostRecentCompileStubPtrGl);
}
// _MD_createTVector
//
// Create a "transition vector" a two word entry containing a ptr to inFunctionMemory
// (the beginning of a compiled function) and a second word containing the environment
// or TOC pointer...currently we always use the system TOC. All other TVector's should
// be acquired from the Formatter objects.
void* _MD_createTVector(const MethodDescriptor& /*inMethodDescriptor*/, void* inFunctionMemory)
{
TVector* newTVector = (TVector*) NativeCodeCache::getCache().acquireMemory(sizeof(TVector));
newTVector->functionPtr = inFunctionMemory;
newTVector->toc = *((void**)_MD_createTVector + 1);
return (newTVector);
}
// BackPatchInfo
//
// little structure used to communicate between the assembly
// stub and the actual compilation and backpatching of the caller
struct BackPatchInfo
{
void** callerTOC; // caller's TOC
JavaObject* thisPtr; // callee this ptr (if a dynamic dispatch, otherwise undefined)
};
// backPatchMethod
//
// Cause the caller to call inMethodAddress next time the call instruction
// is encountered (instead of going through the stub). inLastPC is the next
// PC to be executed upon return from the intended callee (just after the call
// instruction. inUserData is assumed to point to a BackPatchInfo*. (above)
//
// The trick is, that this has to be atomic. That is, atomic from the standpoint
// that any thread entering the caller must not crash, but it would be ok for the
// thread to end up in the compile stub.
//
// For backpatching vtables, we call a routine on the method object which
// does all our dirty work. (It's non-trivial since the same method can occupy
// different positions in a vtable due to interfaces).
// We do the work for static dispatches. Our strategy is to try to use the cheapest
// call-like instruction. See the "General Idea" section at the top of this file
// for details of this strategy.
void* backPatchMethod(void* inMethodAddress, void* inLastPC, void* inUserData)
{
TVector* methodTVector = (TVector*) inMethodAddress;
Uint32* nopOrRestoreToc = (Uint32*) inLastPC;
BackPatchInfo* backPatchInfo = (BackPatchInfo*) inUserData;
// find bl
Uint32* blToPtrGlue = nopOrRestoreToc - 1;
assert ((*blToPtrGlue & kBl) == kBl);
// see where the destination of this bl -- it must be some kind of ptrgl
Int16 offsetToPtrGlue = (Int16) (*blToPtrGlue & 0x000FFFC);
Uint32* ptrGlue = (Uint32*) (((Uint8*) (nopOrRestoreToc - 1)) + offsetToPtrGlue);
if (*ptrGlue == makeDForm(36, 2, 1, 20)) // stw rtoc, 20(sp)
{
// dynamic call
Uint32* dynamicLookup = blToPtrGlue - 1;
assert ((*dynamicLookup & makeDForm(32, 0, 0, 0)) == makeDForm(32, 0, 0, 0)); // lwz r?, offset(rtoc)
Int16 vtableOffset = *dynamicLookup & 0xFFFF; // grab offset in table
// replace value in vtable
((void**)&backPatchInfo->thisPtr->type)[vtableOffset >> 2] = inMethodAddress;
}
else
{
// static call
assert ((*ptrGlue & makeDForm(32, 12, 2, 0)) == makeDForm(32, 12, 2, 0)); // lwz r12, offset(rtoc)
Int32 offsetToCallee;
bool sameTOC = (backPatchInfo->callerTOC == methodTVector->toc);
// first try an absolute branch
// then try a pc-relative branch
// last use the ptr glue (just change the entry in the TOC)
if (sameTOC && (Uint32) methodTVector->functionPtr < 0x3FFFFFF)
{
*blToPtrGlue = kBla | ( (Uint32) methodTVector->functionPtr & 0x03FFFFFF);
blToPtrGlue[1] = kNop;
}
else if (sameTOC && canBePCRelative(blToPtrGlue, methodTVector->functionPtr, offsetToCallee))
{
*blToPtrGlue = (kBl | offsetToCallee); // change bl to branch directly to callee
blToPtrGlue[1] = kNop; // don't restore toc, same toc
}
else
{
Int16 tocOffset = *ptrGlue & 0xFFFF; // grab offset in table
backPatchInfo->callerTOC[tocOffset] = inMethodAddress; // now change the ptr in the table
}
}
return (inMethodAddress);
}
// locate
//
// Assembly glue called by the locateStub to actually locate/compile/etc a
// method and back patch the caller. We save all volatiles (and
// of course save non-volatiles if we use them), fill in a BackPatchInfo
// object, and hand off control to compileAndBackPatchMethod. Upon return
// we restore volatiles, fix up the stack (so it appears we were at the
// callsite in the caller), and jump to the intended callee (returned by
// compileAndBackPatchMethod).
//
// Only one parameter is assumed, r11 = ptr to CacheEntry of method to be located.
// We chose r11 because it is volatile, but not used by any ptr-gl generated by
// the Metrowerks Compilers. We may have to do something slightly different for
// AIX. We may just push the cacheEntry on the stack in the stub, and fix up
// the stack in here.
//
// Currently we only "locate" methods by compilation
asm static void locate()
{
register CacheEntry* cacheEntry;
register void* oldLR;
register TVector* compiledMethod;
BackPatchInfo backPatchInfo;
VolatileRegisters volatileRegisters;
fralloc
mr cacheEntry, r11 // save r11 somewhere else, in case we end up in ptrgl somewhere
mflr oldLR
// save off volatiles
stw r3, backPatchInfo.thisPtr // r3 is saved in backPatchInfo (it is the thisPtr sometimes)
la r3, volatileRegisters // save rest of volatiles
bl saveVolatiles
// fill in the rest of backPatchInfo
lwz r5, 260(SP) // caller's RTOC (260 is a special constant, dependent on amt of stack space used in this function)
stw r5, backPatchInfo.callerTOC
// compileAndBackPatch
mr r3, cacheEntry
mr r4, oldLR
la r5, backPatchInfo
bl compileAndBackPatchMethod // r3 = TVector to actual method
mr compiledMethod, r3 // compiledMethod = TVector to actual method
// restore volatiles
la r3, volatileRegisters
bl restoreVolatiles
lwz r3, backPatchInfo.thisPtr // restore r3
// jmp to the real callee
lwz r0, compiledMethod->functionPtr // r0 = ptr to method
lwz RTOC, compiledMethod->toc // RTOC = toc of compiled method
mtctr r0 // ctr = ptr to method
frfree
bctr
}
// saveVolatiles
//
// Save all non-volatiles except r3 (because it is used for the incoming parameter)
asm void saveVolatiles(register VolatileRegisters *vr)
{
// stw r3, vr->r3
stfd fp0, vr->fp0
stw r4, vr->r4
stfd fp1, vr->fp1
stw r5, vr->r5
stfd fp2, vr->fp2
stw r6, vr->r6
stfd fp3, vr->fp3
stw r7, vr->r7
stfd fp4, vr->fp4
stw r8, vr->r8
stfd fp5, vr->fp5
stw r9, vr->r9
stfd fp6, vr->fp6
stw r10, vr->r10
stfd fp7, vr->fp7
stfd fp8, vr->fp8
stfd fp9, vr->fp9
stfd fp10, vr->fp10
stfd fp11, vr->fp11
stfd fp12, vr->fp12
stfd fp13, vr->fp13
blr
}
// restoreVolatiles
//
// Restore all non-volatiles except r3 (because it is used for the incoming parameter)
asm void restoreVolatiles(register VolatileRegisters *vr)
{
// lwz r3, vr->r3
lfd fp0, vr->fp0
lwz r4, vr->r4
lfd fp1, vr->fp1
lwz r5, vr->r5
lfd fp2, vr->fp2
lwz r6, vr->r6
lfd fp3, vr->fp3
lwz r7, vr->r7
lfd fp4, vr->fp4
lwz r8, vr->r8
lfd fp5, vr->fp5
lwz r9, vr->r9
lfd fp6, vr->fp6
lwz r10, vr->r10
lfd fp7, vr->fp7
lfd fp8, vr->fp8
lfd fp9, vr->fp9
lfd fp10, vr->fp10
lfd fp11, vr->fp11
lfd fp12, vr->fp12
lfd fp13, vr->fp13
blr
}
void *
generateNativeStub(NativeCodeCache& /*inCache*/, const CacheEntry& /*inCacheEntry*/, void * /*nativeFunction*/)
{
trespass("Not implemented");
return 0;
}
// generateCompileStub
//
// Genereate a kLocateStubBytes stub from memory acquired fromn inCache.
// The branches to some ptr-gl which jumps to the actual "locate" routine.
// It is assumed that there is already a reachable compileStubPtrGl, or one
// can be created by calling getCompileStubPtrGl.
extern void*
generateCompileStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry)
{
const size_t kLocateStubBytes = 12;
Uint32* stub = (Uint32*) inCache.acquireMemory(kLocateStubBytes);
Uint32* curPC = stub;
*curPC++ = makeDForm(15, 11, 0, ((Uint32) &inCacheEntry) >> 16); // addis r11, r0, hiword
*curPC++ = makeDForm(24, 11, 11, ((Uint32) &inCacheEntry) & 0xFFFF); // ori r11, r11, loword
*curPC = (kB | (((PRUptrdiff) getCompileStubPtrGl(curPC) - (PRUptrdiff) curPC) & 0x03FFFFFF)); // b compileStubPtrGl
return (_MD_createTVector(inCacheEntry.descriptor, stub));
}

Просмотреть файл

@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// PPC601AppleMacOS_Support.h
//
// Scott M. Silver
#ifndef _H_PPC601APPLEMACOS_SUPPORT
#define _H_PPC601APPLEMACOS_SUPPORT
#include <string.h>
void* getDynamicPtrGl(void* inFromWhere, Uint8 inWhichRegister);
// JitGlobals
//
// Maintains a table of size 2^16
// 16 bit signed offsets are used to load data out of the table
// The gp (or rtoc), therefore, points to the middle of the table
class JitGlobals
{
public:
enum
{
kTOCSize = 0x10000
};
JitGlobals()
{
mBegin = (const Uint8*) new Uint8[kTOCSize];
mGlobalPtr = (const Uint8*) mBegin + (kTOCSize >> 1);
mEnd = (const Uint8*) mBegin + kTOCSize;
mNext = (Uint8*) mBegin;
}
~JitGlobals()
{
delete mBegin;
}
public:
// addData
// Add data beginning at inData of size inSize
// to the JitGlobals. Returns the address of the
// copied data in JG or NULL if the globals are full.
// outOffset is the offset in the table where the data
// was added
void* addData(const void* inData, Uint16 inSize, Uint16 &outOffset)
{
// ¥¥ FIX-ME BEGIN LOCK
Uint16 alignedSize = (inSize + 3) & ~3; // align to 4 bytes
Uint8* dest = mNext;
// make sure we didn't overflow the tbl
if (mNext + alignedSize > mEnd)
return (NULL);
// copy data and return offset into table
memcpy(dest, inData, inSize);
outOffset = dest - mGlobalPtr;
mNext += alignedSize;
return (dest);
// ¥¥ÊFIX-ME END LOCK
}
// toOffset
// Returnns true if inData is in JG. outOffset
// is the offset to the data if its in the table.
bool toOffset(void* inData, Uint16& outOffset)
{
if (inData >= (void*)mBegin && inData < (void*)mNext)
{
outOffset = (Uint8*) inData - mBegin;
return (true);
}
else
return (false);
}
// unsafe, only use if you are the only thread
// who will be touching this table
inline Uint8* getNext() const { return mNext; }
public:
const Uint8* mBegin; // beginning of table
const Uint8* mEnd; // end of table
const Uint8* mGlobalPtr; // what the "global ptr" should point to
private:
Uint8* mNext; // next free entry in table
};
struct TVector
{
void* functionPtr;
void* toc;
};
extern JitGlobals gJitGlobals;
//bool canBePCRelative(void* inStart, void* inDest, Int32& outOffset);
// canBePCRelative
//
inline bool canBePCRelative(void* inStart, void* inDest, Int32& outOffset)
{
outOffset = (PRUptrdiff) inDest - (PRUptrdiff) inStart;
if (inDest > inStart)
return (outOffset < 0x1ffffff);
else
return (outOffset > (Int32) 0xfe000000);
}
extern JitGlobals&
acquireTOC(Uint16 inDesiredAmount);
void* getCompileStubPtrGl(void* inFromWhere);
const uint32 kCrossTocPtrGlBytes = 24;
void* formatCrossTocPtrGl(void* inStart, int16 inTOCOffset);
#ifndef XP_MAC
inline void* getDynamicPtrGl(void* /* inFromWhere */, Uint8 /* inWhichRegister */)
{
return NULL;
}
inline void* formatCrossTocPtrGl(void* /* inStart */, int16 /* inTOCOffset */)
{
return NULL;
}
#endif
// acquireTOC
//
// Try to find a TOC with enough space left in it to fit a desired amount.
// If one cannot be located, create a new TOC and return that.
//
// FIX-ME - right now we only support one TOC
inline JitGlobals&
acquireTOC(Uint16 /*inDesiredAmount*/)
{
static JitGlobals sJitGlobals; // This is a global
return (sJitGlobals);
}
#endif // _H_PPC601APPLEMACOS_SUPPORT

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#if !defined(_PPC601_CPU_H_) || defined(INCLUDE_EMITTER)
#define _PPC601_CPU_H_
#define FIRST_CALLER_SAVED_GR 0
#define LAST_CALLER_SAVED_GR 9
#define FIRST_CALLEE_SAVED_GR 10
#define LAST_CALLEE_SAVED_GR 28
#define FIRST_CALLER_SAVED_FPR 0
#define LAST_CALLER_SAVED_FPR 9
#define FIRST_CALLEE_SAVED_FPR 10
#define LAST_CALLEE_SAVED_FPR 28
#define FIRST_GREGISTER 0
#define LAST_GREGISTER 28
#define FIRST_FPREGISTER 0
#define LAST_FPREGISTER 28
#define NUMBER_OF_SPECIAL_REGISTERS 0
class PPCEmitter;
class PPCFormatter;
typedef PPCFormatter MdFormatter;
typedef PPCEmitter MdEmitter;
#ifdef INCLUDE_EMITTER
#include "PPC601AppleMacOSEmitter.h"
#endif
#define CPU_IS_SUPPORTED
#endif /* _PPC601_CPU_H_ */

Просмотреть файл

@ -0,0 +1,313 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// 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

Просмотреть файл

@ -0,0 +1,168 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// PPCInstructionTemplates.h
//
// Scott M. Silver
// enum name
// opcode
// string
#ifdef DO_DFORM
DFORM_ARITH_DEFINE(Addi, 14)
DFORM_ARITH_DEFINE(Addis, 15)
DFORM_ARITH_DEFINE(Mulli, 7)
DFORM_ARITH_DEFINE(Ori, 24)
DFORM_ARITH_DEFINE(Oris, 25)
DFORM_ARITH_DEFINE(Subfic, 8)
DFORM_ARITH_DEFINE(Xori, 26)
DFORM_ARITH_DEFINE(Xoris, 27)
DFORM_ARITHCC_DEFINE(Addic, 13)
DFORM_ARITHCC_DEFINE(Andi, 28)
DFORM_ARITHCC_DEFINE(Andis, 29)
DFORM_LOAD_DEFINE(Lbz, 34)
DFORM_LOAD_DEFINE(Lfd, 50)
DFORM_LOAD_DEFINE(Lfs, 48)
DFORM_LOAD_DEFINE(Lha, 42)
DFORM_LOAD_DEFINE(Lhz, 40)
DFORM_LOAD_DEFINE(Lwz, 32)
DFORM_LOADU_DEFINE(Lbzu, 35)
DFORM_LOADU_DEFINE(Lfdu, 51)
DFORM_LOADU_DEFINE(Lfsu, 49)
DFORM_LOADU_DEFINE(Lhau, 43)
DFORM_LOADU_DEFINE(Lhzu, 41)
DFORM_LOADU_DEFINE(Lwzu, 33)
DFORM_STORE_DEFINE(Stb, 38)
DFORM_STORE_DEFINE(Stfd, 54)
DFORM_STORE_DEFINE(Stfs, 52)
DFORM_STORE_DEFINE(Sth, 44)
DFORM_STORE_DEFINE(Stw, 36)
DFORM_STOREU_DEFINE(Stu, 39)
DFORM_STOREU_DEFINE(Stfdu, 55)
DFORM_STOREU_DEFINE(Stfsu, 53)
DFORM_STOREU_DEFINE(Sthu, 45)
DFORM_STOREU_DEFINE(Stwu, 37)
DFORM_ARITH_DEFINE(Cmpi, 11)
DFORM_ARITH_DEFINE(Cmpli, 10)
DFORM_TRAP_DEFINE(Twi, 3)
#endif
#ifdef DO_XFORM
XFORM_ARITH_DEFINE(Add, 266, 31)
XFORM_ARITH_DEFINE(Addc, 10, 31)
XFORM_ARITH_DEFINE(Adde, 138, 31)
XFORM_ARITH_DEFINE(Divw, 459, 31)
XFORM_ARITH_DEFINE(Divwu, 138, 31)
XFORM_ARITH_DEFINE(Mulhw, 75, 31)
XFORM_ARITH_DEFINE(Mulhwu, 11, 31)
XFORM_ARITH_DEFINE(Mullw, 235, 31)
XFORM_ARITH_DEFINE(Subf, 40, 31)
XFORM_ARITH_DEFINE(Subfc, 8, 31)
XFORM_ARITH_DEFINE(Subfe, 136, 31)
XFORM_INAONLY_DEFINE(Addme, 234, 31)
XFORM_INAONLY_DEFINE(Addze, 202, 31)
XFORM_INAONLY_DEFINE(Neg, 104, 31)
XFORM_INAONLY_DEFINE(Subfme, 232, 31)
XFORM_INAONLY_DEFINE(Subfze, 200, 31)
XFORM_INAONLY_DEFINE(Srawi, 824-512, 31)
XFORM_ARITH_DEFINE(And, 138, 31)
XFORM_ARITH_DEFINE(Andc, 75, 31)
XFORM_ARITH_DEFINE(Eqv, 284, 31)
XFORM_ARITH_DEFINE(Nand, 476, 31)
XFORM_ARITH_DEFINE(Nor, 124, 31)
XFORM_ARITH_DEFINE(Or, 444, 31)
XFORM_ARITH_DEFINE(Orc, 412, 31)
XFORM_ARITH_DEFINE(Slw, 24, 31)
XFORM_ARITH_DEFINE(Sraw, 792, 31) // FIX-ME prob isn't correct
XFORM_ARITH_DEFINE(Srw, 536, 31) // FIX-ME prob isn't corect
XFORM_ARITH_DEFINE(Xor, 316, 31)
XFORM_CMP_DEFINE(Cmp, 0, 31)
XFORM_CMP_DEFINE(Cmpl, 32, 31)
XFORM_CMP_DEFINE(Fcmpo, 0, 63)
XFORM_CMP_DEFINE(Fcmpu, 32, 63)
XFORM_LOAD_DEFINE(Lbzx, 87, 31)
XFORM_LOAD_DEFINE(Lfdx, 599, 31) // FIX-ME prob isn't corect
XFORM_LOAD_DEFINE(Lfsx, 535, 31)
XFORM_LOAD_DEFINE(Lhax, 343, 31)
XFORM_LOAD_DEFINE(Lhbrx, 790, 31) // FIX-ME prob isn't corect
XFORM_LOAD_DEFINE(Lhzx, 279, 31)
XFORM_LOAD_DEFINE(Lwarx, 20, 31)
XFORM_LOAD_DEFINE(Lwbrx, 534, 31) // FIX-ME prob isn't corect
XFORM_LOAD_DEFINE(Lwzx, 23, 31)
XFORM_LOADU_DEFINE(Lbzux, 119, 31)
XFORM_LOADU_DEFINE(Lfdux, 631, 31) // FIX-ME prob isn't corect
XFORM_LOADU_DEFINE(Lfsux, 567, 31) // FIX-ME prob isn't corect
XFORM_LOADU_DEFINE(Lhaux, 375, 31)
XFORM_LOADU_DEFINE(Lhzux, 311, 31)
XFORM_LOADU_DEFINE(Lwzux, 55, 31)
XFORM_STORE_DEFINE(Stbx, 215, 31)
XFORM_STORE_DEFINE(Stfdx, 727, 31) // FIX-ME prob isn't corect
XFORM_STORE_DEFINE(Stfsx, 663, 31) // FIX-ME prob isn't corect
XFORM_STORE_DEFINE(Sthbrx, 918, 31) // FIX-ME prob isn't corect
XFORM_STORE_DEFINE(Sthx, 407, 31)
XFORM_STORE_DEFINE(Stwbrx, 662, 31) // FIX-ME prob isn't corect
XFORM_STORE_DEFINE(Stwx, 151, 31)
XFORM_STOREU_DEFINE(Stbux, 247, 31)
XFORM_STOREU_DEFINE(Stfdux, 759, 31) // FIX-ME prob isn't corect
XFORM_STOREU_DEFINE(Stfsux, 695, 31) // FIX-ME prob isn't corect
XFORM_STOREU_DEFINE(Sthux, 439, 31)
XFORM_STOREU_DEFINE(Stwux, 183, 31)
/* X Form - TrapWord */
XFORM_TRAP_DEFINE(Tw, 4, 31)
/* X Form - XInBOnly */
XFORM_INBONLY_DEFINE(Fabs, 264, 63)
XFORM_INBONLY_DEFINE(Fctiw, 14, 63)
XFORM_INBONLY_DEFINE(Fctiwz, 15, 63)
XFORM_INBONLY_DEFINE(Fmr, 72, 63)
XFORM_INBONLY_DEFINE(Fnabs, 136, 63)
XFORM_INBONLY_DEFINE(Fneg, 40, 63)
XFORM_INBONLY_DEFINE(Frsp, 12, 63)
#endif
#ifdef DO_MFORM
MFORM_DEFINE(Rlwimi, 20)
MFORM_DEFINE(Rlwinm, 21)
MFORM_DEFINE(Rlwnm, 23)
#endif
#ifdef DO_AFORM
// name, opcode, xo, has A (ie A != 0), has B, hasC, sets CC (ie Rc)
AFORM_DEFINE(Fadd, 63, 21, true, true, false, false)
AFORM_DEFINE(FaddC, 63, 21, true, true, false, true)
#endif DO_AFORM

Просмотреть файл

@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// PPCInstructions.cpp
//
// Scott M. Silver
#include "PPCInstructions.h"
#include "PPC601AppleMacOSEmitter.h"
/* Instantiate templates explicitly if needed */
#ifdef MANUAL_TEMPLATES
template class AForm<true, true, false, true>;
template class AForm<true, true, false, false>;
#endif
void DFormXY::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
struct
{
uint OPCD:6;
uint D:5;
uint A:5;
uint IMM:16;
} dForm;
dForm.OPCD = sDFormInfos[mKind].opcode;
dForm.D = getD();
dForm.A = getA();
dForm.IMM = getIMM();
*(Uint32*) inStart = *(Uint32*) &dForm;
}
void LdD_RTOC::
formatToMemory(void* inStart, Uint32 inOffset, PPCFormatter& inFormatter)
{
mImmediate += inFormatter.mRealTOCOffset;
LdD_FixedSource<2>::formatToMemory(inStart, inOffset, inFormatter);
}
void XFormXY::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
struct
{
uint OPCD:6;
uint D:5;
uint A:5;
uint B:5;
uint OE:1;
uint XO:9;
uint RC:1;
} xForm;
xForm.OPCD = sXFormInfos[mKind].primary;;
xForm.D = getD();
xForm.A = getA();
xForm.B = getB();
xForm.OE = ((mFlags & pfOE) != 0) ? 1 : 0;
xForm.XO = sXFormInfos[mKind].opcode;
xForm.RC = ((mFlags & pfRc) != 0) ? 1 : 0;
*(Uint32*) inStart = *(Uint32*) &xForm;
}
void BranchI::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/)
{
mIForm.LI = (mTarget.getNativeOffset() - inOffset) >> 2;
*(Uint32*) inStart = *(Uint32*) &mIForm;
}
void BranchCB::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/)
{
mCForm.BD = (mTarget.getNativeOffset() - inOffset) >> 2;
*(Uint32*) inStart = *(Uint32*) &mCForm;
}
BranchCB::
BranchCB(DataNode* inPrimitive, Pool& inPool, ControlNode& inTarget, Condition2 inCondition, bool inAbsolute, bool inLink) :
PPCInstructionXY(inPrimitive, inPool, 1, 0),
mTarget(inTarget)
#if DEBUG
, mCond(inCondition)
#endif
{
mCForm.OPCD = 16;
mCForm.BO = sBranchConditions[inCondition].bo;
// mCForm.Y = 0;
mCForm.BI = sBranchConditions[inCondition].bi;
mCForm.AA = inAbsolute;
mCForm.LK = inLink;
}
void MForm::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
struct
{
uint OPCD:6;
uint S:5;
uint A:5;
uint B:5;
uint MB:5;
uint ME:5;
uint RC:1;
} mForm;
mForm.OPCD = sMFormInfos[mKind].opcode;
mForm.S = getS();
mForm.A = getA();
mForm.B = getB();
mForm.MB = getMB();
mForm.ME = getME();
mForm.RC = ((mFlags & pfRc) != 0) ? 1 : 0;
*(Uint32*) inStart = *(Uint32*) &mForm;
}

Просмотреть файл

@ -0,0 +1,955 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// PPCInstructions.h
//
// Scott M. Silver
// Peter Desantis
#ifndef _H_PPCINSTRUCTIONS
#define _H_PPCINSTRUCTIONS
#include "prtypes.h"
#include "Instruction.h"
#include "ControlNodes.h"
typedef Uint8 PPCInsnFlags;
enum
{
pfNil = 0x00, // nothing special
pfRc = 0x01, // sets a condition code
pfOE = 0x02 // set the overflow flag
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊPPCInstructionXY ¥
#endif
// PPCInstructionXY
//
// Base class for all PPC instructions
class PPCInstructionXY :
public InsnUseXDefineYFromPool
{
public:
inline PPCInstructionXY(DataNode* inPrimitive, Pool& inPool, Uint8 inX, Uint8 inY) :
InsnUseXDefineYFromPool(inPrimitive, inPool, inX, inY) { }
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return (4); }
};
// Fixed point color to register map.
const Uint8 sFixedPointRegisterMap[] =
{
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, // -> first non-volatile
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
19, 18, 17, 16, 15, 14 // 13 // -> last non-volatile, but used as globals
};
const Uint8 sFloatingPointRegisterMap[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, // -> first non-volatile
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31 // -> last non-volatile
};
// udToRegisterNumber
//
// Map colors of registers to real register numbers
inline Uint8
udToRegisterNumber(InstructionUseOrDefine& inUse)
{
Uint32 color = inUse.getVirtualRegister().colorInfo.color;
if (inUse.getVirtualRegister().getClass() == vrcInteger)
{
if (color < sizeof(sFixedPointRegisterMap) / sizeof(Uint8))
return (sFixedPointRegisterMap[color]);
#ifdef DEBUG
else
return 255;
#endif
}
else if (inUse.getVirtualRegister().getClass() == vrcFloatingPoint)
{
if (color < sizeof(sFloatingPointRegisterMap) / sizeof(Uint8))
return (sFloatingPointRegisterMap[color]);
#ifdef DEBUG
else
return 255;
#endif
}
else
assert(false);
return 255; // never reached
}
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊD-Form ¥
#endif
#define MAKE_DFORM_ENUM(inName) df##inName,
#define DFORM_ARITH_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DFORM_ARITHCC_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DFORM_LOAD_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DFORM_LOADU_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DFORM_STORE_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DFORM_STOREU_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DFORM_TRAP_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
#define DO_DFORM
enum DFormKind
{
#include "PPCInstructionTemplates.h"
dfLast
};
#undef DFORM_ARITH_DEFINE
#undef DFORM_ARITHCC_DEFINE
#undef DFORM_LOAD_DEFINE
#undef DFORM_LOADU_DEFINE
#undef DFORM_STORE_DEFINE
#undef DFORM_STOREU_DEFINE
#undef DFORM_TRAP_DEFINE
struct DFormInstructionInfo
{
Uint16 opcode;
char* formatStr;
};
#define MAKE_DFORM_INFO(inOpcode, inString) \
{ inOpcode, inString },
#define DFORM_ARITH_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, r%d, %d")
#define DFORM_ARITHCC_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, r%d, %d")
#define DFORM_LOAD_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
#define DFORM_LOADU_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
#define DFORM_STORE_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
#define DFORM_STOREU_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
#define DFORM_TRAP_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName"%s r%d, %d")
const DFormInstructionInfo sDFormInfos[] =
{
#include "PPCInstructionTemplates.h"
};
#undef DO_DFORM
class DFormXY :
public PPCInstructionXY
{
public:
inline DFormXY(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint8 inX, Uint8 inY) :
PPCInstructionXY(inPrimitive, inPool, inX, inY),
mKind(inKind) { }
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
protected:
Uint8 getOPCD() { return (sDFormInfos[mKind].opcode); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
virtual Uint16 getIMM() = 0;
const Uint16 mKind;
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) {fprintf(f, sDFormInfos[mKind].formatStr, getD(), getA(), getIMM());}
#endif
};
class DFormXYImmediate :
public DFormXY
{
public:
inline DFormXYImmediate(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint8 inX, Uint8 inY, Uint16 inImmediate) :
mImmediate(inImmediate),
DFormXY(inPrimitive, inPool, inKind, inX, inY) { }
virtual Uint16 getIMM() { return mImmediate; }
Uint16 mImmediate; // immediate value
};
template<Uint8 tUses, Uint8 tDefines, Uint8 tAOffset, Uint8 tDOffset>
class LdD :
public DFormXYImmediate
{
public:
inline LdD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
DFormXYImmediate(inPrimitive, inPool, inKind, tUses, tDefines, inImmediate) { }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[tAOffset])); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[tDOffset])); }
};
template<Uint8 tFixedSourceRegister>
class LdD_FixedSource :
public LdD<0, 1, 0, 0>
{
public:
inline LdD_FixedSource(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
LdD<0, 1, 0, 0>(inPrimitive, inPool, inKind, inImmediate) { assert (tFixedSourceRegister < 32); }
virtual Uint8 getA() { return (tFixedSourceRegister); }
};
// the formatToMemory routine does a fix-up
// based on the real toc offset
class LdD_RTOC :
public LdD_FixedSource<2>
{
public:
inline LdD_RTOC(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
LdD_FixedSource<2>(inPrimitive, inPool, inKind, inImmediate) { }
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter);
};
typedef LdD<2, 1, 1, 0> LdD_; // Rvalue | mem Raddress
typedef LdD<2, 2, 1, 1> LdD_V; // mem Rvalue | mem Raddress
// Rvalue | Sstackslot
class LdD_SpillRegister :
public LdD<1, 1, 0, 0>
{
public:
inline LdD_SpillRegister(DataNode* inPrimitive, Pool& inPool, VirtualRegister& inStackSlot, VirtualRegister& inDefine) :
LdD<1, 1, 0, 0>(inPrimitive, inPool, dfLwz, 0) { addUse(0, inStackSlot); addDefine(0, inDefine); }
// FIX-ME what about 64 bit fregs.
virtual Uint16 getIMM() { return ((Uint16)(getInstructionUseBegin()[0].getVirtualRegister().getColor() * -4) - 4); }
virtual Uint8 getA() { return (1); }
};
// --
// mem | mem Raddress Rvalue
class StD :
public DFormXYImmediate
{
public:
inline StD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Int16 inImmediate, Uint8 inUses = 3, Uint8 inDefines = 1) :
DFormXYImmediate(inPrimitive, inPool, inKind, inUses, inDefines, inImmediate) { }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[2])); }
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) {fprintf(f, sDFormInfos[mKind].formatStr, getD(), getA(), getIMM());}
#endif
};
// Sstackslot | Rvalue
class StD_SpillRegister :
public StD
{
public:
inline StD_SpillRegister(DataNode* inPrimitive, Pool& inPool, VirtualRegister& inStackSlot, VirtualRegister& inUse) :
StD(inPrimitive, inPool, dfStw, 0, 1, 1) { addDefine(0, inStackSlot); addUse(0, inUse); }
virtual Uint16 getIMM() { return ((Uint16)(getInstructionUseBegin()[0].getVirtualRegister().getColor() * -4) - 4); }
virtual Uint8 getA() { return (1); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
};
// mem | mem value
template<Uint8 tFixedDestRegister>
class StD_FixedDestRegister :
public StD
{
public:
inline StD_FixedDestRegister(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
StD(inPrimitive, inPool, inKind, inImmediate, 2, 1) { }
virtual Uint8 getA() { return (tFixedDestRegister); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
};
class ArithID :
public DFormXYImmediate
{
public:
inline ArithID(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Int16 inImmediate) :
DFormXYImmediate(inPrimitive, inPool, inKind, 1, 1, inImmediate) { }
virtual InstructionFlags getFlags() const { return ((mImmediate == 0 && mKind == dfAddi) ? ifCopy : ifNone); }
};
class LogicalID :
public DFormXYImmediate
{
public:
inline LogicalID(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Int16 inImmediate) :
DFormXYImmediate(inPrimitive, inPool, inKind, 1, 1, inImmediate) { }
Uint8 getA() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
virtual InstructionFlags getFlags() const { return ((mImmediate == 0 && mKind == dfAddi) ? ifCopy : ifNone); }
};
class ArithIZeroInputD :
public DFormXYImmediate
{
public:
inline ArithIZeroInputD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate, Uint8 inFakeUses = 0) :
DFormXYImmediate(inPrimitive, inPool, inKind, inFakeUses, 1, inImmediate) { }
Uint8 getA() { return (0); }
};
class LogicalIZeroInputD :
public DFormXYImmediate
{
public:
inline LogicalIZeroInputD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate, Uint8 inFakeUses = 0) :
DFormXYImmediate(inPrimitive, inPool, inKind, inFakeUses, 1, inImmediate) { }
Uint8 getA() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
Uint8 getD() { return (0); }
};
class Copy_I :
public ArithID
{
public:
inline Copy_I(DataNode* inPrimitive, Pool& inPool) :
ArithID(inPrimitive, inPool, dfAddi, 0) { }
};
class ArithIDSetCC :
public DFormXYImmediate
{
public:
inline ArithIDSetCC(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
DFormXYImmediate(inPrimitive, inPool, inKind, 2, 2, inImmediate) { }
};
class CmpID :
public DFormXYImmediate
{
public:
inline CmpID(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
DFormXYImmediate(inPrimitive, inPool, inKind, 1, 1, inImmediate) { }
protected:
virtual Uint8 getD() { return (0); } // always use cr0, and L=0
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, sDFormInfos[mKind].formatStr, getD() >> 2, getA(), getIMM()); }
#endif
};
// the bits in order (or offsets into a condition register)
// neg (lt)
// pos (gt)
// zero (eq)
// summary overflow (so)
// 0010y branch if cond is false
// 0110y branch if cond is true
struct TrapCondition
{
char* name;
Uint8 to;
};
// indexed by Condition2
static TrapCondition sSignedTrapConditions[] =
{
{"", 31},
{"lt", 16},
{"eq", 4},
{"le", 20},
{"gt", 8},
{"ne", 24},
{"ge", 12}
};
// indexed by Condition2
static TrapCondition sUnsignedTrapConditions[] =
{
{"", 31},
{"llt", 2},
{"eq", 4},
{"lle", 6},
{"lgt", 1},
{"ne", 24},
{"lge", 5}
};
class TrapD :
public DFormXYImmediate
{
public:
inline TrapD(DataNode* inPrimitive, Pool& inPool, Condition2 inCondition, bool inSigned, Uint16 inImmediate) :
DFormXYImmediate(inPrimitive, inPool, dfTwi, 1, 0, inImmediate),
mSigned(inSigned),
mCond(inCondition) { }
protected:
virtual Uint8 getD() { return (mSigned ? sSignedTrapConditions[mCond].to : sUnsignedTrapConditions[mCond].to); }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
const bool mSigned;
const Condition2 mCond;
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, sDFormInfos[mKind].formatStr, mSigned ? sSignedTrapConditions[mCond].name : sUnsignedTrapConditions[mCond].name, getA(), getIMM()); }
#endif
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊX & XO-Form ¥
#endif
#define MAKE_XFORM_ENUM(inName) xf##inName,
#define XFORM_ARITH_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_INAONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_CMP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_LOAD_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_LOADU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_STORE_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_STOREU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_TRAP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define XFORM_INBONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
#define DO_XFORM
enum XFormKind
{
#include "PPCInstructionTemplates.h"
xfLast
};
#undef XFORM_ARITH_DEFINE
#undef XFORM_INAONLY_DEFINE
#undef XFORM_CMP_DEFINE
#undef XFORM_LOAD_DEFINE
#undef XFORM_LOADU_DEFINE
#undef XFORM_STORE_DEFINE
#undef XFORM_STOREU_DEFINE
#undef XFORM_TRAP_DEFINE
#undef XFORM_INBONLY_DEFINE
struct XFormInstructionInfo
{
Uint16 opcode;
Uint16 primary;
char* formatStr;
};
#define MAKE_XFORM_INFO(inOpcode, inPrimary, inString) \
{ inOpcode, inPrimary, inString },
#define XFORM_ARITH_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_INAONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_CMP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_LOAD_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_LOADU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_STORE_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_STOREU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_TRAP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
#define XFORM_INBONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
const XFormInstructionInfo sXFormInfos[] =
{
#include "PPCInstructionTemplates.h"
};
#undef DO_XFORM
static char*
sFlagsExtensionTbl[] =
{
"", // none
".", // pfRc
"o", // pfOE
"o." // pfRC | afOE
};
class XFormXY :
public PPCInstructionXY
{
public:
inline XFormXY(DataNode* inPrimitive, Pool& inPool, Uint8 inX, Uint8 inY, XFormKind inKind, PPCInsnFlags inFlags) :
PPCInstructionXY(inPrimitive, inPool, inX, inY),
mFlags(inFlags),
mKind(inKind) { }
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
protected:
virtual Uint8 getOPCD() { return (31); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
virtual Uint16 getXO() { return (sXFormInfos[mKind].opcode); }
PPCInsnFlags mFlags;
XFormKind mKind;
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, sXFormInfos[mKind].formatStr, flagsToExtension(), getD(), getA(), getB()); }
const char* flagsToExtension() { return sFlagsExtensionTbl[mFlags & 3]; } // only look at OE and Rc bits
#endif
};
class TrapX :
public XFormXY
{
public:
inline TrapX(DataNode* inPrimitive, Pool& inPool, Condition2 inCondition, bool inSigned, PPCInsnFlags inFlags) :
XFormXY(inPrimitive, inPool, 2, 0, xfTw, inFlags),
mSigned(inSigned),
mCond(inCondition) { }
protected:
virtual Uint8 getD() { return (mSigned ? sSignedTrapConditions[mCond].to : sUnsignedTrapConditions[mCond].to); }
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, sXFormInfos[mKind].formatStr, mSigned ? sSignedTrapConditions[mCond].name : sUnsignedTrapConditions[mCond].name, getA(), getB()); }
#endif
protected:
bool mSigned;
Condition2 mCond;
};
template<Uint8 inX, Uint8 inY, Uint8 inD, Uint8 inA, Uint8 inB>
class LdX :
public XFormXY
{
public:
inline LdX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind) :
XFormXY(inPrimitive, inPool, inX, inY, inKind, pfNil) { assert(inKind >= xfLbzx && inKind <= xfLwzx); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[inD])); }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[inA])); }
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[inB])); }
};
typedef LdX<2, 1, 0, 0, 1> LdX_C; // Rvalue <- Raddress Radddress
typedef LdX<3, 2, 1, 1, 2> LdX_V; // mem Rvalue Raddress <- mem Raddress Raddress
typedef LdX<3, 1, 0, 1, 2> LdX_; // Rvalue <- mem Raddress Raddress
// mem <- mem Raddress Raddress Value
class StX :
public XFormXY
{
public:
inline StX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind) :
XFormXY(inPrimitive, inPool, 4, 1, inKind, pfNil) { assert(inKind >= xfStbx && inKind <= xfStwx); }
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[3])); }
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[2])); }
};
class ArithX :
public XFormXY
{
public:
inline ArithX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
XFormXY(inPrimitive, inPool, 2, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, inFlags) { }
};
class XOInAOnly :
public XFormXY
{
public:
// if we want to use the lswi, need to deal with memory edge
inline XOInAOnly(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
XFormXY(inPrimitive, inPool, 1, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, inFlags) {}
protected:
virtual Uint8 getA() { return 0; }
};
class XInAOnly :
public XFormXY
{
public:
// if we want to use the lswi, need to deal with memory edge
inline XInAOnly(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags, Uint8 inB) :
XFormXY(inPrimitive, inPool, 1, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, (inFlags | pfOE)),
mB(inB) { }
protected:
virtual Uint8 getD() { return (XFormXY::getA()); }
virtual Uint8 getA() { return (XFormXY::getD()); }
virtual Uint8 getB() { assert (mB < (1 << 6)); return mB; }
Uint8 mB;
};
class XInBOnly :
public XFormXY
{
public:
inline XInBOnly(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
XFormXY(inPrimitive, inPool, 1, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, inFlags) { }
protected:
virtual Uint8 getA() { return (0); }
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
virtual InstructionFlags getFlags() const { return ((mKind == xfFmr) ? ifCopy : ifNone); }
Uint8 mA;
};
class CmpIX :
public XFormXY
{
public:
inline CmpIX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
XFormXY(inPrimitive, inPool, 2, 1, inKind, inFlags) { }
protected:
virtual Uint8 getD() { return (0); } // always use cr0
};
class CmpFX :
public XFormXY
{
public:
inline CmpFX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
XFormXY(inPrimitive, inPool, 2, 1, inKind, inFlags) { }
protected:
virtual Uint8 getD() { return (0); } // always use cr0
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊIForm ¥
#endif
class BranchI :
public PPCInstructionXY
{
public:
inline BranchI(DataNode* inPrimitive, Pool& inPool, ControlNode& inTarget, bool inAbsolute = false, bool inLink = false) :
PPCInstructionXY(inPrimitive, inPool, 0, 0), mTarget(inTarget)
{ mIForm.OPCD = 18; mIForm.LI = 0; mIForm.AA = inAbsolute; mIForm.LK = inLink;}
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
#ifdef DEBUG
virtual void printPretty(FILE* f) { fprintf(f, "bxx %d", mTarget.getNativeOffset()); }
#endif
protected:
ControlNode& mTarget;
struct
{
int OPCD:6;
int LI:24;
int AA:1;
int LK:1;
} mIForm;
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊIForm ¥
#endif
// the bits in order (or offsets into a condition register)
// neg (lt)
// pos (gt)
// zero (eq)
// summary overflow (so)
// 0010y branch if cond is false
// 0110y branch if cond is true
struct BranchCondition
{
char* name;
Uint8 bo;
Uint8 bi;
};
// indexed by Condition2
const BranchCondition sBranchConditions[] =
{
{"always", 0, 0},
{"lt", 12, 0},
{"eq", 12, 2},
{"le", 4, 1},
{"gt", 12, 1},
{"ne", 4, 2},
{"ge", 4, 0}
};
#if 0
BO BI
cond0, // 0000 Always false
condLt, // 0001 arg1 < arg2 0110y 0 lt
condEq, // 0010 arg1 = arg2 0110y 2 eq
condLe, // 0011 arg1 <= arg2 0010y 1 not gt
condGt, // 0100 arg1 > arg2 0110y 1 gt
condLgt, // 0101 arg1 <> arg2 0010y 2 not eq
condGe, // 0110 arg1 >= arg2 0010y 0 not lt
-- only up to these are supported
condOrd, // 0111 arg1 <=> arg2 (i.e. arg1 and arg2 are ordered) 0110y 3 so ?? nan
condUnord, // 1000 arg1 ? arg2 (i.e. arg1 and arg2 are unordered) 0010y 3 not so
condULt, // 1001 arg1 ?< arg2 do we have to deal with these below here??
condUEq, // 1010 arg1 ?= arg2
condULe, // 1011 arg1 ?<= arg2
condUGt, // 1100 arg1 ?> arg2
condNe, // 1101 arg1 != arg2
condUGe, // 1110 arg1 ?>= arg2
cond1 // 1111 Always true
#endif
class BranchCB :
public PPCInstructionXY
{
public:
BranchCB(DataNode* inPrimitive, Pool& inPool, ControlNode& inTarget, Condition2 inCondition, bool inAbsolute = false, bool inLink = false);
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
protected:
ControlNode& mTarget;
struct
{
unsigned int OPCD:6;
unsigned int BO:5;
// unsigned int Y:1;
unsigned int BI:5;
unsigned int BD:14;
unsigned int AA:1;
unsigned int LK:1;
} mCForm;
#if DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, "b%s %d", sBranchConditions[mCond].name, mTarget.getNativeOffset()); }
protected:
Condition2 mCond;
#endif
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊM-Form ¥
#endif
#define DO_MFORM
struct MFormInstructionInfo
{
Uint16 opcode;
char* formatStr;
};
#define MAKE_MFORM_ENUM(inName) mf##inName,
#define MFORM_DEFINE(inName, inOpcode) MAKE_MFORM_ENUM(inName)
enum MFormKind
{
#include "PPCInstructionTemplates.h"
mfLast
};
#undef MFORM_DEFINE
#define MAKE_MFORM_INFO(inName, inOpcode) \
{ inOpcode, #inName"%s r%d, r%d, r%d, %d, %d"},
#define MFORM_DEFINE(inName, inOpcode) MAKE_MFORM_INFO(inName, inOpcode)
const MFormInstructionInfo sMFormInfos[] =
{
#include "PPCInstructionTemplates.h"
};
#undef MFORM_DEFINE
#undef DO_MFORM
class MForm :
public PPCInstructionXY
{
public:
inline MForm(DataNode* inPrimitive, Pool& inPool, Uint8 inUses, MFormKind inKind, Uint8 inMaskBegin, Uint8 inMaskEnd, PPCInsnFlags inFlags) :
PPCInstructionXY(inPrimitive, inPool, inUses, 1 + (bool) (inFlags & pfRc)),
mFlags(inFlags),
mKind(inKind),
mMaskBegin(inMaskBegin),
mMaskEnd(inMaskEnd) { }
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
protected:
Uint16 getOPCD() { return (sXFormInfos[mKind].opcode); }
Uint8 getS() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
Uint8 getA() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
Uint8 getMB() { return (mMaskBegin); }
Uint8 getME() { return (mMaskEnd); }
#ifdef DEBUG
public:
virtual void printPretty(FILE* f) { fprintf(f, sMFormInfos[mKind].formatStr, flagsToExtension(), getA(), getS(), getB(), getMB(), getME()); }
protected:
const char* flagsToExtension() { return sFlagsExtensionTbl[mFlags & 1]; /* only look at Rc bit */ }
#endif
PPCInsnFlags mFlags;
MFormKind mKind;
Uint8 mMaskBegin;
Uint8 mMaskEnd;
};
class MFormInAOnly :
public MForm
{
public:
inline MFormInAOnly(DataNode* inPrimitive, Pool& inPool, MFormKind inKind, Uint8 inB, Uint8 inMaskBegin, Uint8 inMaskEnd, PPCInsnFlags inFlags) :
MForm(inPrimitive, inPool, 1, inKind, inMaskBegin, inMaskEnd, inFlags),
mB(inB) { }
protected:
virtual Uint8 getB() { return (mB); }
Uint8 mB;
};
#ifdef __MWERKS__
#pragma mark -
#pragma mark ¥ÊA-Form ¥
#endif
#define DO_AFORM
#define MAKE_AFORM_ENUM(inName) af##inName,
#define AFORM_DEFINE(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc) MAKE_AFORM_ENUM(inName)
enum AFormKind
{
#include "PPCInstructionTemplates.h"
afLast
};
#undef AFORM_DEFINE
template <bool tHasA, bool tHasB, bool tHasC, bool tRc>
class AForm :
public PPCInstructionXY
{
public:
inline AForm(DataNode* inPrimitive, Pool& inPool, AFormKind inKind) :
PPCInstructionXY(inPrimitive, inPool, tHasA + tHasB + tHasC, tRc + 1),
mKind(inKind) {}
protected:
Uint16 getOPCD() { return (sAFormInfos[mKind].opcode); }
Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
Uint8 getA() { return (tHasA ? udToRegisterNumber(getInstructionUseBegin()[0]) : 0); }
Uint8 getB() { return (tHasB ? udToRegisterNumber(getInstructionUseBegin()[tHasA]) : 0); }
Uint8 getC() { return (tHasC ? udToRegisterNumber(getInstructionUseBegin()[tHasA + tHasB]) : 0); }
public:
virtual void
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
struct
{
uint OPCD:6;
uint D:5;
uint A:5;
uint B:5;
uint C:5;
uint XO:5;
uint RC:1;
} aForm;
aForm.OPCD = sAFormInfos[mKind].opcode;
aForm.D = getD();
aForm.A = getA();
aForm.B = getB();
aForm.C = getC();
aForm.XO = sAFormInfos[mKind].xo;
aForm.RC = tRc;
*(Uint32*) inStart = *(Uint32*) &aForm;
}
static Instruction&
createInstruction(DataNode& inPrimitive, Pool& mPool, AFormKind inKind)
{
return *new(mPool) AForm<tHasA, tHasB, tHasC, tRc>(&inPrimitive, mPool, inKind);
}
protected:
const AFormKind mKind;
#ifdef DEBUG
public:
virtual void printPretty(FILE* /*f*/) {}
protected:
const char* flagsToExtension() { return sFlagsExtensionTbl[tRc]; } // only look at Rc bit
#endif
};
struct AFormInstructionInfo
{
Uint16 opcode;
Uint16 xo;
Instruction& (*creatorFunction)(DataNode&, Pool&, AFormKind);
char* formatStr;
};
#define MAKE_AFORM_INFO(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc) \
{ inOpcode, inXo, AForm<inHasA, inHasB, inHasC, inRc>::createInstruction, #inName"%s r%d, r%d, r%d, %d, %d"},
#define AFORM_DEFINE(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc) MAKE_AFORM_INFO(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc)
const AFormInstructionInfo sAFormInfos[] =
{
#include "PPCInstructionTemplates.h"
};
#undef AFORM_DEFINE
#undef DO_AFORM
#endif // _H_PPCINSTRUCTIONS

Просмотреть файл

@ -0,0 +1,41 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
# ppc-makefile.mac
#
# Scott M. Silver
#
# Assuming MOZ_SRC was set up (to point to the directory above ns), this
# makefile generates the PrimitiveOperations and CodeGenerator specific
# stuff (including BURG, etc)
NAD_SRC = "{MOZ_SRC}:ns:electricalfire:Compiler:CodeGenerator:md:ppc:ppc601-macos.nad"
PRIMITIVEOPERATIONS = "{MOZ_SRC}:ns:electricalfire:Compiler:PrimitiveGraph:PrimitiveOperations"
NAD = {PERL} "{MOZ_SRC}:ns:electricalfire:Tools:Nad:Nad.pl"
NAD_OUTPUTS = {NAD_SRC}.burg.h {NAD_SRC}.burg.cpp {PRIMITIVEOPERATIONS}.h {PRIMITIVEOPERATIONS}.cpp
{NAD_OUTPUTS} Ä {NAD_SRC} {PRIMITIVEOPERATIONS}
{NAD} {NAD_SRC} {PRIMITIVEOPERATIONS} {PRIMITIVEOPERATIONS}.h {PRIMITIVEOPERATIONS}.cpp {NAD_SRC}.burg.h > BurgOut
BURG -I <BurgOut > {NAD_SRC}.burg.cpp
set TouchedFiles "`ResolveAlias {PRIMITIVEOPERATIONS}.h`"
set TouchedFiles "{TouchedFiles},`ResolveAlias {NAD_SRC}.burg.h`"
set TouchedFiles "{TouchedFiles},`ResolveAlias {NAD_SRC}.burg.cpp`"
set TouchedFiles "{TouchedFiles},`ResolveAlias {PRIMITIVEOPERATIONS}.cpp`"
export TouchedFiles

Просмотреть файл

@ -0,0 +1,406 @@
%top
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
%
Vptr <- Vint()
Vint <- Vptr()
Vint <- poConst_I() cost(1)
%{
genPrimConst_32(thisPrimitive);
%}
Vptr <- poConst_A() cost(1)
%{
genPrimConst_32(thisPrimitive);
%}
Vfloat <- poConst_F() cost(1)
%{
Flt32 constant = (*static_cast<const PrimConst *>(&thisPrimitive)).value.f;
Uint16 offset;
mAccumulatorTOC.addData(&constant, sizeof(constant), offset);
Instruction& ldConstant = *new(mPool) LdD_RTOC(&thisPrimitive, mPool, dfLfs, offset);
defineProducer(thisPrimitive, ldConstant, 0, vrcFloatingPoint);
%}
Result <- poResult_I(Vint inResult) cost(1)
%{
genPrimResult_32(thisPrimitive, inResult);
%}
Result <- poResult_A(Vptr inResult) cost(1)
%{
genPrimResult_32(thisPrimitive, inResult);
%}
Result <- poResult_F(Vfloat inResult) cost(1)
%{
VirtualRegister* returnVr;
// generate: fmr fp0, fpResultRegister
// create a buffer copy instruction between the result
// and the precolored register
XInBOnly& copyInsn = *new(mPool) XInBOnly(&thisPrimitive, mPool, xfFmr, pfNil);
useProducer(inResult, copyInsn, 0, vrcFloatingPoint);
returnVr = &defineTemporary(copyInsn, 0, vrcFloatingPoint);
// floating point results go somwhere FIX-ME
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(&thisPrimitive, mPool, 1);
useTemporaryVR(externalUse, *returnVr, 0, vrcFloatingPoint);
thisPrimitive.setInstructionRoot(&externalUse);
%}
#define IF_CONTROL(inPrimOp, inCondition) \
Control <- inPrimOp(Vcond) cost(1) \
%{ \
genBranch(thisPrimitive, inCondition); \
%}
IF_CONTROL(poIfLt, condLt)
IF_CONTROL(poIfNe, condNe)
IF_CONTROL(poIfEq, condEq)
IF_CONTROL(poIfLe, condLe)
IF_CONTROL(poIfGt, condGt)
IF_CONTROL(poIfLgt, condLgt)
IF_CONTROL(poIfGe, condGe)
Vint <- poAnd_I(Vint inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfAnd, inA, inB);
%}
Vint <- poOr_I(Vint inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfOr, inA, inB);
%}
Vint <- poXor_I(Vint inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfXor, inA, inB);
%}
Vint <- poAnd_I(Vint inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfAnd, inA, inB);
%}
Vint <- poAdd_I(Vint inA, coConstS16 inConstant) cost(1)
%{
genArithD_32(thisPrimitive, dfAddi, inA, PrimConst::cast(inConstant).value.i);
%}
Vint <- poAdd_I(coConstS16 inConstant, Vint inB) cost(1)
%{
genArithD_32(thisPrimitive, dfAddi, inB, PrimConst::cast(inConstant).value.i);
%}
Vint <- poAdd_I(Vptr inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfAdd, inA, inB);
%}
Vptr <- poAddU_A(Vptr inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfAdd, inA, inB);
%}
Vptr <- poAdd_A(Vptr inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfAdd, inA, inB);
%}
Vint <- poSub_I(Vptr inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfSubf, inB, inA);
%}
Vptr <- poSub_A(Vptr inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfSubf, inB, inA);
%}
Vint <- poMul_I(Vint inA, Vint inB) cost(1)
%{
genArithX_32(thisPrimitive, xfMullw, inA, inB);
%}
Vint <- poDiv_I(Vint inDividend, Vint inDivisor) cost(1)
%{
genArithX_32(thisPrimitive, xfDivw, inDividend, inDivisor);
%}
Vint <- poDivE_I(Vint inDividend, Vint inDivisor) cost(1)
%{
// FIX-ME must handle divide by zero system exception
genArithX_32(thisPrimitive, xfDivw, inDividend, inDivisor);
%}
Vint <- poDivU_I(Vint inDividend, Vint inDivisor) cost(1)
%{
genArithX_32(thisPrimitive, xfDivwu, inDividend, inDivisor);
%}
Vint <- poDivUE_I(Vint inDividend, Vint inDivisor) cost(1)
%{
// FIX-ME must handle divide by zero system exception
genArithX_32(thisPrimitive, xfDivwu, inDividend, inDivisor);
%}
Vint <- poMod_I(Vint inDividend, Vint inDivisor) cost(1)
%{
genMod(thisPrimitive, xfDivw, inDividend, inDivisor);
%}
Vint <- poModE_I(Vint inDividend, Vint inDivisor) cost(1)
%{
// FIX-ME must handle divide by zero system exception
genMod(thisPrimitive, xfDivw, inDividend, inDivisor);
%}
Vint <- poModU_I(Vint inDividend, Vint inDivisor) cost(1)
%{
// FIX-ME must handle divide by zero system exception
genMod(thisPrimitive, xfDivwu, inDividend, inDivisor);
%}
Vint <- poShl_I(Vint inValue, Vint inShiftAmount) cost(1)
%{
XOutA& newInsn = *new(mPool) XOutA(&thisPrimitive, mPool, xfSlw, pfNil);
useProducer(inValue, newInsn, 0);
useProducer(inShiftAmount, newInsn, 1);
defineProducer(thisPrimitive, newInsn, 0);
%}
Vfloat <- poFAdd_F(Vfloat inA, Vfloat inB) cost(1)
%{
genArith_FP(thisPrimitive, afFadd, inA, inB);
%}
Vcond <- poCmp_I(Vint inA, Vint inB) cost(1)
%{
CmpIX& newInsn = *new(mPool) CmpIX(&thisPrimitive, mPool, xfCmp, 0);
useProducer(inA, newInsn, 0);
useProducer(inB, newInsn, 1);
defineProducer(thisPrimitive, newInsn, 0);
%}
Vcond <- poCmpU_I(Vint inA, Vint inB) cost(1)
%{
CmpIX& newInsn = *new(mPool) CmpIX(&thisPrimitive, mPool, xfCmpl, 0);
useProducer(inA, newInsn, 0);
useProducer(inB, newInsn, 1);
defineProducer(thisPrimitive, newInsn, 0);
%}
Exception <- poChkNull(Vptr inTestValue) cost(1)
%{
genThrowIfZero(thisPrimitive, inTestValue);
%}
Exception <- poLimit(Vint inIndex, Vint inBound) cost(1)
%{
TrapX& newInsn = *new(mPool) TrapX(&thisPrimitive, mPool, condGe, false, pfNil);
useProducer(inIndex, newInsn, 0);
useProducer(inBound, newInsn, 1);
thisPrimitive.setInstructionRoot(&newInsn);
%}
#define LD_FIXED(inPrimOp, inReturnType, inOpcode) \
inReturnType <- inPrimOp(Vptr[1] inAddress) cost(1) \
%{ \
genLd_Fixed(thisPrimitive, inOpcode, inAddress); \
%}
#define LDE_FIXED(inPrimOp, inReturnType, inOpcode) \
inReturnType <- inPrimOp(Vptr[1] inAddress) cost(1) \
%{ \
genThrowIfZero(thisPrimitive, inAddress); \
genLd_Fixed(thisPrimitive, inOpcode, inAddress); \
%}
#define LD_SEX(inPrimOp, inLdOpcode, inSexOpcode) \
Vint <- inPrimOp(Vptr[1] inAddress) cost(1) \
%{ \
genLd_Fixed(thisPrimitive, inLdOpcode, inAddress); \
\
XInAOnly &ext = *new(mPool) XInAOnly(&thisPrimitive, mPool, inSexOpcode, pfNil, 0); \
useProducer(thisPrimitive, ext, 0); \
defineProducer(thisPrimitive, ext, 0); \
%}
#define LDE_SEX(inPrimOp, inLdOpcode, inSexOpcode) \
Vint <- inPrimOp(Vptr[1] inAddress) cost(1) \
%{ \
genThrowIfZero(thisPrimitive, inAddress); \
genLd_Fixed(thisPrimitive, inLdOpcode, inAddress); \
\
XInAOnly &ext = *new(mPool) XInAOnly(&thisPrimitive, mPool, inSexOpcode, pfNil, 0); \
useProducer(thisPrimitive, ext, 0); \
defineProducer(thisPrimitive, ext, 0); \
%}
#define LD_FLOATING(inPrimOp, inReturnType, inOpcode) \
inReturnType <- inPrimOp(Vptr[1] inAddress) cost(1) \
%{ \
genLd_FP(thisPrimitive, inOpcode, inAddress); \
%}
#define LDE_FLOATING(inPrimOp, inReturnType, inOpcode) \
inReturnType <- inPrimOp(Vptr[1] inAddress) cost(1) \
%{ \
genThrowIfZero(thisPrimitive, inAddress); \
genLd_FP(thisPrimitive, inOpcode, inAddress); \
%}
LD_FIXED(poLd_I, Vint, dfLwz)
LD_FIXED(poLd_A, Vptr, dfLwz)
LD_FLOATING(poLd_F, Vfloat, dfLfs)
LDE_FIXED(poLdE_I, Vint, dfLwz)
LDE_FIXED(poLdE_A, Vptr, dfLwz)
LDE_FLOATING(poLdE_F, Vfloat, dfLfs)
LD_SEX(poLdS_B, dfLbz, xfExtsb)
LD_SEX(poLdS_H, dfLhz, xfExtsh)
LDE_SEX(poLdS_B, dfLbz, xfExtsb)
LDE_SEX(poLdS_H, dfLhz, xfExtsh)
LD_FIXED(poLdU_B, Vint, dfLbz)
LD_FIXED(poLdU_H, Vint, dfLhz)
LDE_FIXED(poLdUE_B, Vint, dfLbz)
LDE_FIXED(poLdUE_H, Vint, dfLhz)
Store <- poSt_B(Vptr[1] inAddress, Vint inValue) cost(1)
%{
genSt(thisPrimitive, dfStb, inAddress, inValue);
%}
Store <- poSt_H(Vptr[1] inAddress, Vint inValue) cost(1)
%{
genSt(thisPrimitive, dfSth, inAddress, inValue);
%}
Store <- poSt_I(Vptr[1] inAddress, Vint inValue) cost(1)
%{
genSt(thisPrimitive, dfStw, inAddress, inValue);
%}
Store <- poSt_F(Vptr[1] inAddress, Vfloat inValue) cost(1)
%{
genSt(thisPrimitive, dfStfs, inAddress, inValue);
%}
Store <- poSt_A(Vptr[1] inAddress, Vptr inValue) cost(1)
%{
genSt(thisPrimitive, dfStw, inAddress, inValue);
%}
Store <- poStE_B(Vptr[1] inAddress, Vint inValue) cost(1)
%{
genThrowIfZero(thisPrimitive, inAddress); // FIX-ME eliminate on AIX
genSt(thisPrimitive, dfStb, inAddress, inValue);
%}
Store <- poStE_H(Vptr[1] inAddress, Vint inValue) cost(1)
%{
genThrowIfZero(thisPrimitive, inAddress); // FIX-ME eliminate on AIX
genSt(thisPrimitive, dfSth, inAddress, inValue);
%}
Store <- poStE_I(Vptr[1] inAddress, Vint inValue) cost(1)
%{
genThrowIfZero(thisPrimitive, inAddress); // FIX-ME eliminate on AIX
genSt(thisPrimitive, dfStw, inAddress, inValue);
%}
Store <- poStE_F(Vptr[1] inAddress, Vfloat inValue) cost(1)
%{
genThrowIfZero(thisPrimitive, inAddress); // FIX-ME eliminate on AIX
genSt(thisPrimitive, dfStfs, inAddress, inValue);
%}
Store <- poStE_A(Vptr[1] inAddress, Vptr inValue) cost(1)
%{
genThrowIfZero(thisPrimitive, inAddress); // FIX-ME eliminate on AIX
genSt(thisPrimitive, dfStw, inAddress, inValue);
%}
Tuple <- poSysCall() cost(1)
%{
CallS_& newInsn = *new CallS_(&thisPrimitive, mPool, CallS_::numberOfArguments(thisPrimitive), CallS_::hasReturnValue(thisPrimitive), *this, PrimSysCall::cast(thisPrimitive).sysCall.function);
%}
Tuple <- poSysCallE() cost(1)
%{
CallS_& newInsn = *new CallS_(&thisPrimitive, mPool, CallS_::numberOfArguments(thisPrimitive), CallS_::hasReturnValue(thisPrimitive), *this, PrimSysCall::cast(thisPrimitive).sysCall.function);
%}
Tuple <- poSysCallC() cost(1)
%{
CallS_C& newInsn = *new CallS_C(&thisPrimitive, mPool, CallS_C::numberOfArguments(thisPrimitive), CallS_C::hasReturnValue(thisPrimitive), *this, PrimSysCall::cast(thisPrimitive).sysCall.function);
%}
Tuple <- poSysCallEC() cost(1)
%{
CallS_C& newInsn = *new CallS_C(&thisPrimitive, mPool, CallS_C::numberOfArguments(thisPrimitive), CallS_C::hasReturnValue(thisPrimitive), *this, PrimSysCall::cast(thisPrimitive).sysCall.function);
%}
Tuple <- poSysCallV() cost(1)
%{
CallS_V& newInsn = *new CallS_V(&thisPrimitive, mPool, CallS_V::numberOfArguments(thisPrimitive), CallS_V::hasReturnValue(thisPrimitive), *this, PrimSysCall::cast(thisPrimitive).sysCall.function);
%}
Tuple <- poSysCallEV() cost(1)
%{
CallS_V& newInsn = *new CallS_V(&thisPrimitive, mPool, CallS_V::numberOfArguments(thisPrimitive), CallS_V::hasReturnValue(thisPrimitive), *this, PrimSysCall::cast(thisPrimitive).sysCall.function);
%}
Tuple <- poCall(Vptr) cost(1)
%{
// Dynamic call
CallD_& newInsn = *new CallD_(&thisPrimitive, mPool, CallD_::numberOfArguments(thisPrimitive), CallD_::hasReturnValue(thisPrimitive), *this);
%}
Tuple <- poCall(poConst_A) cost(1)
%{
// Static call
Call_& newInsn = *new Call_(&thisPrimitive, mPool, Call_::numberOfArguments(thisPrimitive), Call_::hasReturnValue(thisPrimitive), *this);
%}

Просмотреть файл

@ -0,0 +1,286 @@
%top
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Burg.h"
%
%terminals
%
%startsymbols
Control
Result
Exception
Store
Vcond
Vint
Vlong
Vfloat
Vdouble
Vptr
Cint
Clong
Cfloat
Cdouble
Cptr
Tuple
%
%grammar
Vint: coReg_I $1 $
Vlong: coReg_L $1 $
Vfloat: coReg_F $1 $
Vdouble: coReg_D $1 $
Vptr: coReg_A $1 $
Vcond: coReg_C $1 $
Store: coReg_M $1 $
Cint: coReg_I $1 $
Clong: coReg_L $1 $
Cfloat: coReg_F $1 $
Cdouble: coReg_D $1 $
Cptr: coReg_A $1 $
Vint: poConst_I $1 $emConst_I
Vlong: poConst_L $1 $emConst_L
Vfloat: poConst_F $1 $emConst_F
//Vdouble: poConst_D $1 $emConst_D
Vptr: poConst_A $1 $emConst_A
//Vcond: poConst_C $1 $emConst_C
//Store: poBreak(Store) $1 $emBreak
Vint: poArg_I $1 $
Vlong: poArg_L $1 $
Vfloat: poArg_F $1 $
Vdouble: poArg_D $1 $
Vptr: poArg_A $1 $
Store: poArg_M $1 $
Result: poResult_I(Vint) $1 $emResult_I
//Result: poResult_L(Vlong) $1 $emResult_L
Result: poResult_F(Vfloat) $1 $emResult_F
//Result: poResult_D(Vdouble) $1 $emResult_D
Result: poResult_A(Vptr) $1 $emResult_A
Result: poResult_M(Store) $1 $
Control: poIfLt(Vcond) $1 $emIfLt
Control: poIfEq(Vcond) $1 $emIfEq
Control: poIfLe(Vcond) $1 $emIfLe
Control: poIfGt(Vcond) $1 $emIfGt
Control: poIfLgt(Vcond) $1 $emIfLgt
Control: poIfGe(Vcond) $1 $emIfGe
Control: poIfOrd(Vcond) $1 $emIfOrd
//Control: poIfUnord(Vcond) $1 $emIfUnord
Control: poIfULt(Vcond) $1 $emIfULt
Control: poIfUEq(Vcond) $1 $emIfUEq
Control: poIfULe(Vcond) $1 $emIfULe
Control: poIfUGt(Vcond) $1 $emIfUGt
Control: poIfNe(Vcond) $1 $emIfNe
Control: poIfUGe(Vcond) $1 $emIfUGe
//Control: poSwitch(Vint) $1 $emSwitch
Vint: poAnd_I(Vint, Vint) $1 $emAnd_I
Vlong: poAnd_L(Vlong, Vlong) $1 $emAnd_L
Vint: poOr_I(Vint, Vint) $1 $emOr_I
Vlong: poOr_L(Vlong, Vlong) $1 $emOr_L
Vint: poXor_I(Vint, Vint) $1 $emXor_I
Vlong: poXor_L(Vlong, Vlong) $1 $emXor_L
Vint: poAdd_I(Vint, Vint) $1 $emAdd_I
//Vlong: poAdd_L(Vlong, Vlong) $1 $emAdd_L
Vptr: poAdd_A(Vptr, Vint) $1 $emAdd_A
Vptr: poAddU_A(Vptr, Vint) $1 $emAddU_A
Vint: poSub_I(Vint, Vint) $1 $emSub_I
//Vlong: poSub_L(Vlong, Vlong) $1 $emSub_L
Vptr: poSub_A(Vptr, Vint) $1 $emSub_A
Vptr: poSubU_A(Vptr, Vint) $1 $emSubU_A
Vint: poSubA_I(Vptr, Vptr) $1 $emSubA_I
Vint: poMul_I(Vint, Vint) $1 $emMul_I
//Vlong: poMul_L(Vlong, Vlong) $1 $emMul_L
Vint: poDiv_I(Vint, Vint) $1 $emDiv_I
//Vint: poDiv_L(Vlong, Vlong) $1 $emDiv_L
Vint: poDivE_I(Vint, Vint) $1 $emDivE_I
//Vint: poDivE_L(Vlong, Vlong) $1 $emDivE_L
Vint: poDivU_I(Vint, Vint) $1 $emDivU_I
//Vint: poDivU_L(Vlong, Vlong) $1 $emDivU_L
Vint: poDivUE_I(Vint, Vint) $1 $emDivUE_I
//Vint: poDivUE_L(Vlong, Vlong) $1 $emDivUE_L
Vint: poMod_I(Vint, Vint) $1 $emMod_I
//Vint: poMod_L(Vlong, Vlong) $1 $emMod_L
Vint: poModE_I(Vint, Vint) $1 $emModE_I
//Vint: poModE_L(Vlong, Vlong) $1 $emModE_L
//Vint: poModU_I(Vint, Vint) $1 $emModU_I
//Vint: poModU_L(Vlong, Vlong) $1 $emModU_L
//Vint: poModUE_I(Vint, Vint) $1 $emModUE_I
//Vint: poModUE_L(Vlong, Vlong) $1 $emModUE_L
Vint: poShl_I(Vint, Vint) $1 $emShl_I
//Vlong: poShl_L(Vlong, Vint) $1 $emShl_L
//Vint: poShr_I(Vint, Vint) $1 $emShr_I
//Vlong: poShr_L(Vlong, Vint) $1 $emShr_L
//Vint: poShrU_I(Vint, Vint) $1 $emShrU_I
//Vlong: poShrU_L(Vlong, Vint) $1 $emShrU_L
//Vint: poExt_I(Vint, Cint) $1 $emExt_I
//Vlong: poExt_L(Vlong, Cint) $1 $emExt_L
Vfloat: poFAdd_F(Vfloat, Vfloat) $1 $emFAdd_F
//Vdouble: poFAdd_D(Vdouble, Vdouble) $1 $emFAdd_D
//Vfloat: poFSub_F(Vfloat, Vfloat) $1 $emFSub_F
//Vdouble: poFSub_D(Vdouble, Vdouble) $1 $emFSub_D
//Vfloat: poFMul_F(Vfloat, Vfloat) $1 $emFMul_F
//Vdouble: poFMul_D(Vdouble, Vdouble) $1 $emFMul_D
//Vfloat: poFDiv_F(Vfloat, Vfloat) $1 $emFDiv_F
//Vdouble: poFDiv_D(Vdouble, Vdouble) $1 $emFDiv_D
//Vfloat: poFRem_F(Vfloat, Vfloat) $1 $emFRem_F
//Vdouble: poFRem_D(Vdouble, Vdouble) $1 $emFRem_D
//Vint: poConvI_L(Vlong) $1 $emConvI_L
//Vlong: poConvL_I(Vint) $1 $emConvL_I
//Vint: poFConvI_F(Vfloat) $1 $emFConvI_F
//Vint: poFConvI_D(Vdouble) $1 $emFConvI_D
//Vlong: poFConvL_F(Vfloat) $1 $emFConvL_F
//Vlong: poFConvL_D(Vdouble) $1 $emFConvL_D
//Vfloat: poFConvF_I(Vint) $1 $emFConvF_I
//Vfloat: poFConvF_L(Vlong) $1 $emFConvF_L
//Vfloat: poFConvF_D(Vdouble) $1 $emFConvF_D
//Vdouble: poFConvD_I(Vint) $1 $emFConvD_I
//Vdouble: poFConvD_L(Vlong) $1 $emFConvD_L
//Vdouble: poFConvD_F(Vfloat) $1 $emFConvD_F
Vcond: poCmp_I(Vint, Vint) $1 $emCmp_I
//Vcond: poCmp_L(Vlong, Vlong) $1 $emCmp_L
//Vcond: poCmpU_I(Vint, Vint) $1 $emCmpU_I
//Vcond: poCmpU_L(Vlong, Vlong) $1 $emCmpU_L
//Vcond: poCmpU_A(Vptr, Vptr) $1 $emCmpU_A
//Vcond: poFCmp_F(Vfloat, Vfloat) $1 $emFCmp_F
//Vcond: poFCmp_D(Vdouble, Vdouble) $1 $emFCmp_D
//Vint: poLt_I(Vcond) $1 $emLt_I
//Vint: poEq_I(Vcond) $1 $emEq_I
//Vint: poLe_I(Vcond) $1 $emLe_I
//Vint: poGt_I(Vcond) $1 $emGt_I
//Vint: poLgt_I(Vcond) $1 $emLgt_I
//Vint: poGe_I(Vcond) $1 $emGe_I
//Vint: poOrd_I(Vcond) $1 $emOrd_I
//Vint: poUnord_I(Vcond) $1 $emUnord_I
//Vint: poULt_I(Vcond) $1 $emULt_I
//Vint: poUEq_I(Vcond) $1 $emUEq_I
//Vint: poULe_I(Vcond) $1 $emULe_I
//Vint: poUGt_I(Vcond) $1 $emUGt_I
//Vint: poNe_I(Vcond) $1 $emNe_I
//Vint: poUGe_I(Vcond) $1 $emUGe_I
//Vint: poCatL_I(Vcond) $1 $emCatL_I
//Vint: poCatG_I(Vcond) $1 $emCatG_I
//Vint: poCatCL_I(Vcond) $1 $emCatCL_I
//Vint: poCatCG_I(Vcond) $1 $emCatCG_I
Exception: poChkNull(Vptr) $1 $emChkNull
Exception: poLimit(Vint, Vint) $1 $emLimit
Vint: poLd_I(Vptr) $1 $emLd_I
//Vlong: poLd_L(Vptr) $1 $emLd_L
//Vfloat: poLd_F(Vptr) $1 $emLd_F
//Vdouble: poLd_D(Vptr) $1 $emLd_D
Vptr: poLd_A(Vptr) $1 $emLd_A
//Vint: poLdE_I(Cptr) $1 $emLdE_I
//Vlong: poLdE_L(Cptr) $1 $emLdE_L
//Vfloat: poLdE_F(Cptr) $1 $emLdE_F
//Vdouble: poLdE_D(Cptr) $1 $emLdE_D
//Vptr: poLdE_A(Cptr) $1 $emLdE_A
//Vint: poLdS_B(Vptr) $1 $emLdS_B
//Vint: poLdS_H(Vptr) $1 $emLdS_H
//Vint: poLdSE_B(Cptr) $1 $emLdSE_B
//Vint: poLdSE_H(Cptr) $1 $emLdSE_H
//Vint: poLdU_B(Vptr) $1 $emLdU_B
//Vint: poLdU_H(Vptr) $1 $emLdU_H
//Vint: poLdUE_B(Cptr) $1 $emLdUE_B
//Vint: poLdUE_H(Cptr) $1 $emLdUE_H
//Vint: poLdV_I(Vptr) $1 $emLdV_I
//Vlong: poLdV_L(Vptr) $1 $emLdV_L
//Vfloat: poLdV_F(Vptr) $1 $emLdV_F
//Vdouble: poLdV_D(Vptr) $1 $emLdV_D
//Vptr: poLdV_A(Vptr) $1 $emLdV_A
//Vint: poLdVE_I(Cptr) $1 $emLdVE_I
//Vlong: poLdVE_L(Cptr) $1 $emLdVE_L
//Vfloat: poLdVE_F(Cptr) $1 $emLdVE_F
//Vdouble: poLdVE_D(Cptr) $1 $emLdVE_D
//Vptr: poLdVE_A(Cptr) $1 $emLdVE_A
Vint: poLd_I(poAdd_A(Vptr, Cint)) $0 $emLd_IRegisterIndirect
Vptr: poLd_A(poAdd_A(Vptr, Cint)) $0 $emLd_ARegisterIndirect
//Store: poSt_B(Vptr, Vint) $1 $emSt_B
//Store: poSt_H(Vptr, Vint) $1 $emSt_H
Store: poSt_I(Vptr, Vint) $1 $emSt_I
//Store: poSt_L(Vptr, Vlong) $1 $emSt_L
//Store: poSt_F(Vptr, Vfloat) $1 $emSt_F
//Store: poSt_D(Vptr, Vdouble) $1 $emSt_D
//Store: poSt_A(Vptr, Vptr) $1 $emSt_A
//Store: poStE_B(Cptr, Vint) $1 $emStE_B
//Store: poStE_H(Cptr, Vint) $1 $emStE_H
//Store: poStE_I(Cptr, Vint) $1 $emStE_I
//Store: poStE_L(Cptr, Vlong) $1 $emStE_L
//Store: poStE_F(Cptr, Vfloat) $1 $emStE_F
//Store: poStE_D(Cptr, Vdouble) $1 $emStE_D
//Store: poStE_A(Cptr, Vptr) $1 $emStE_A
//Store: poStV_B(Vptr, Vint) $1 $emStV_B
//Store: poStV_H(Vptr, Vint) $1 $emStV_H
//Store: poStV_I(Vptr, Vint) $1 $emStV_I
//Store: poStV_L(Vptr, Vlong) $1 $emStV_L
//Store: poStV_F(Vptr, Vfloat) $1 $emStV_F
//Store: poStV_D(Vptr, Vdouble) $1 $emStV_D
//Store: poStV_A(Vptr, Vptr) $1 $emStV_A
//Store: poStVE_B(Cptr, Vint) $1 $emStVE_B
//Store: poStVE_H(Cptr, Vint) $1 $emStVE_H
//Store: poStVE_I(Cptr, Vint) $1 $emStVE_I
//Store: poStVE_L(Cptr, Vlong) $1 $emStVE_L
//Store: poStVE_F(Cptr, Vfloat) $1 $emStVE_F
//Store: poStVE_D(Cptr, Vdouble) $1 $emStVE_D
//Store: poStVE_A(Cptr, Vptr) $1 $emStVE_A
Store: poSt_I(poAdd_A(Vptr, poConst_I), Vint) $0 $emSt_IRegisterIndirect
Store: poProj_M $1 $
Vint: poProj_I $1 $
Vptr: poProj_A $1 $
Tuple: poSysCall $1 $emSysCall
Tuple: poSysCallE $1 $emSysCallE
Tuple: poSysCallC $1 $emSysCallC
Tuple: poSysCallEC $1 $emSysCallEC
Tuple: poSysCallV $1 $emSysCallV
Tuple: poSysCallEV $1 $emSysCallEV
Tuple: poCall(Vptr) $1 $emDynamicCall
Tuple: poCall(poConst_A) $1 $emStaticCall
%

Просмотреть файл

@ -0,0 +1,72 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../../..
MODULE_NAME = sparc
include $(DEPTH)/config/config.mk
INCLUDES += \
-I$(DEPTH)/Utilities/General \
-I$(DEPTH)/Utilities/zlib \
-I$(DEPTH)/Runtime/ClassReader \
-I$(DEPTH)/Compiler/FrontEnd \
-I$(DEPTH)/Runtime/NativeMethods \
-I$(DEPTH)/Runtime/System \
-I$(DEPTH)/Compiler/PrimitiveGraph \
-I$(DEPTH)/Runtime/ClassInfo \
-I$(DEPTH)/Runtime/FileReader \
-I$(DEPTH)/Compiler/CodeGenerator \
-I$(DEPTH)/Compiler/CodeGenerator/md \
-I$(DEPTH)/Compiler/RegisterAllocator \
$(NULL)
CXXSRCS = \
SparcInstruction.cpp \
SparcSunOSEmitter.cpp \
sparc.nad.burg.cpp \
$(NULL)
include $(DEPTH)/config/rules.mk
export:: sparc.nad.burg.cpp
libs:: $(MODULE)
#
# Rules to generate sparc.nad.burg.[cpp][h]
#
sparc.nad.burg.cpp: sparc.nad.burg $(BURG)
$(BURG) -I -o $@ < $<
sparc.nad.burg: sparc.nad $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations $(DEPTH)/Tools/Nad/nad.pl
$(PERL) $(DEPTH)/Tools/Nad/nad.pl $< $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.h \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.cpp \
$<.burg.h > $@
#
# Extra cleaning
#
clobber::
rm -f sparc.nad.burg.cpp sparc.nad.burg.h sparc.nad.burg
realclean clobber_all::
rm -f sparc.nad.burg.cpp sparc.nad.burg.h sparc.nad.burg

Просмотреть файл

@ -0,0 +1,297 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SparcInstruction.h"
#include "ControlNodes.h"
SparcInstructionInfo siInfo[nSparcInstructionKind] =
{
{ siAnd, 2, 0x01, "and" },
{ siAndCC, 2, 0x11, "andcc" },
{ siAndN, 2, 0x05, "andn" },
{ siAndNCC, 2, 0x15, "andncc" },
{ siOr, 2, 0x02, "or" },
{ siOrCC, 2, 0x12, "orcc" },
{ siOrN, 2, 0x06, "orn" },
{ siOrNCC, 2, 0x16, "orncc" },
{ siXor, 2, 0x03, "xor" },
{ siXorCC, 2, 0x13, "xorcc" },
{ siXNor, 2, 0x07, "xnor" },
{ siXNorCC, 2, 0x17, "xnorcc" },
{ siSll, 2, 0x25, "sll" },
{ siSrl, 2, 0x26, "srl" },
{ siSra, 2, 0x27, "sra" },
{ siAdd, 2, 0x00, "add" },
{ siAddCC, 2, 0x10, "addcc" },
{ siAddX, 2, 0x08, "addx" },
{ siAddXCC, 2, 0x18, "addxcc" },
{ siSub, 2, 0x04, "sub" },
{ siSubCC, 2, 0x14, "subcc" },
{ siSubX, 2, 0x0c, "subx" },
{ siSubXCC, 2, 0x1c, "subxcc" },
{ siUMul, 2, 0x0a, "umul" },
{ siUMulCC, 2, 0x1a, "umulcc" },
{ siSMul, 2, 0x0b, "smul" },
{ siSMulCC, 2, 0x1b, "smulcc" },
{ siUDiv, 2, 0x0e, "udiv" },
{ siUDivCC, 2, 0x1e, "udivcc" },
{ siSDiv, 2, 0x0f, "sdiv" },
{ siSDivCC, 2, 0x1f, "sdvicc" },
{ siTrap, 2, 0x3a, "trap" },
{ siLdSb, 3, 0x09, "ldsb" },
{ siLdSh, 3, 0x0a, "ldsh" },
{ siLdUb, 3, 0x01, "ldub" },
{ siLdUh, 3, 0x02, "lduh" },
{ siLd, 3, 0x00, "ld" },
{ siLdd, 3, 0x03, "ldd" },
{ siStSb, 3, 0x05, "stsb" },
{ siStSh, 3, 0x06, "stsh" },
{ siSt, 3, 0x04, "st" },
{ siStd, 3, 0x07, "std" },
{ siBranch, 0, 0x02, "b" },
};
SparcAccessInfo saInfo[nSparcAccessKind] =
{
{ saRRR, 2, 1 },
{ saRIR, 1, 1 },
{ saRZR, 1, 1 },
{ saZRR, 1, 1 },
{ saZIR, 0, 1 },
{ saZZR, 0, 1 },
{ saRRZ, 2, 0 },
{ saRIZ, 1, 0 },
{ saRZZ, 1, 0 },
};
SparcConditionInfo scInfo[nSparcConditionKind] =
{
{ scA, 0x08, "a" },
{ scN, 0x00, "n" },
{ scNe, 0x09, "ne" },
{ scE, 0x01, "e" },
{ scG, 0x0a, "g" },
{ scLe, 0x02, "le" },
{ scGe, 0x0b, "ge" },
{ scL, 0x03, "l" },
{ scGu, 0x0c, "gu" },
{ scLeu, 0x04, "leu" },
{ scCc, 0x0d, "cc" },
{ scGeu, 0x0d, "cc" },
{ scCs, 0x05, "cs" },
{ scLu, 0x05, "cs" },
{ scPos, 0x0e, "pos" },
{ scNeg, 0x06, "neg" },
{ scVc, 0x0f, "vc" },
{ scVs, 0x07, "vs" }
};
char* registerNumberToString[] =
{
"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
};
uint8 registerNumberToColor[] =
{
255, 255, 255, 255, 255, 255, 255, 255,
8, 9, 10, 11, 12, 13, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7,
14, 15, 16, 17, 18, 19, 255, 255
};
SparcRegisterNumber colorToRegisterNumber[] =
{
l0, l1, l2, l3, l4, l5, l6, l7,
o0, o1, o2, o3, o4, o5,
i0, i1, i2, i3, i4, i5,
};
void SparcFormatBCond::
formatToMemory(void* inStart, uint32 inOffset)
{
uint32 insn = 0;
insn |= (siInfo[kind].op & 0x3) << 30;
if (a) insn |= (1 << 29);
insn |= (scInfo[cond].cond & 0xf) << 25;
insn |= (siInfo[kind].op3 & 0x7) << 22;
insn |= ((target.getNativeOffset() - inOffset) >> 2) & 0x3fffff;
*(uint32*) inStart = insn;
if (a) ((uint32*) inStart)[1] = 1 << 24;
}
void SparcFormatC::
formatToMemory(void* inStart, uint32 /*inOffset*/)
{
uint32 insn = 0;
insn |= (siInfo[kind].op & 0x3) << 30;
insn |= (getRD() & 0x1f) << 25;
insn |= (siInfo[kind].op3 & 0x3f) << 19;
insn |= (getRS1() & 0x1f) << 14;
if (imm13)
insn |= (imm13 | 0x2000);
else
insn |= getRS2();
*(uint32*) inStart = insn;
}
void SparcFormatC::
printPretty(FILE* f)
{
switch (access)
{
case saRIR: case saZIR: case saRIZ:
fprintf(f, "%s %%%s,%d,%%%s", siInfo[kind].string,
registerNumberToString[getRS1()],
imm13,
registerNumberToString[getRD()]);
break;
default:
fprintf(f, "%s %%%s,%%%s,%%%s", siInfo[kind].string,
registerNumberToString[getRS1()],
registerNumberToString[getRS2()],
registerNumberToString[getRD()]);
}
}
void SparcLoadStore::
printPretty(FILE* f)
{
switch (access)
{
case saRIR: case saRZR:
if (isLoad)
fprintf(f, "%s [%%%s+%d],%%%s", siInfo[kind].string,
registerNumberToString[getRS1()],
imm13,
registerNumberToString[getRD()]);
else
fprintf(f, "%s %%%s,[%%%s+%d]", siInfo[kind].string,
registerNumberToString[getRD()],
registerNumberToString[getRS1()],
imm13);
break;
default:
if (isLoad)
fprintf(f, "%s [%%%s+%%%s],%%%s", siInfo[kind].string,
registerNumberToString[getRS1()],
registerNumberToString[getRS2()],
registerNumberToString[getRD()]);
else
fprintf(f, "%s %%%s,[%%%s+%%%s]", siInfo[kind].string,
registerNumberToString[getRD()],
registerNumberToString[getRS1()],
registerNumberToString[getRS2()]);
break;
}
}
void SparcTrap::
printPretty(FILE* f)
{
fprintf(f, "t%s throw_exception", scInfo[cond].string);
}
void SparcFormatBCond::
printPretty(FILE* f)
{
fprintf(f, "%s%s%s N%d%s", siInfo[kind].string, scInfo[cond].string, a ? ",a" : "",
target.dfsNum, a ? "; nop" : "");
}
uint8 SparcFormatC::
getRS1()
{
switch (access)
{
case saZRR: case saZIR: case saZZR:
return g0;
default:
return useToRegisterNumber(getInstructionUseBegin()[0]);
}
}
uint8 SparcFormatC::
getRS2()
{
#if DEBUG
if (access == saRIR || access == saZIR || access == saRIZ) assert(0);
#endif
switch (access)
{
case saZZR: case saRZZ: case saRZR:
return g0;
default:
return useToRegisterNumber(getInstructionUseBegin()[1]);
}
}
uint8 SparcFormatC::
getRD()
{
switch (access)
{
case saRRZ: case saRIZ: case saRZZ:
return g0;
default:
return defineToRegisterNumber(getInstructionDefineBegin()[0]);
}
}
uint8 SparcLoadStore::
getRS1()
{
switch (access)
{
case saZRR: case saZIR: case saZZR:
return g0;
default:
return useToRegisterNumber(getInstructionUseBegin()[isLoadC ? 0 : 1]);
}
}
uint8 SparcLoadStore::
getRS2()
{
assert(0);
}
uint8 SparcLoadStore::
getRD()
{
switch (access)
{
case saRRZ: case saRIZ: case saRZZ:
return g0;
default:
return (isLoad) ? defineToRegisterNumber(getInstructionDefineBegin()[hasMemoryEdge ? 1 : 0]) :
useToRegisterNumber(getInstructionUseBegin()[2]);
}
}

Просмотреть файл

@ -0,0 +1,318 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPARC_INSTRUCTION_H_
#define _SPARC_INSTRUCTION_H_
#include "Fundamentals.h"
#include "Instruction.h"
//
// Instruction format A (op=1): CALL
//
// |31 |29 0|
// |-----------------------------------------------------------------------------------------------|
// | op | disp30 |
// |-----------------------------------------------------------------------------------------------|
//
//
// Instruction format B (op=0): SETHI & Branches
//
// |31 |29|28 |24 |21 0|
// |-----------------------------------------------------------------------------------------------|
// | op | rd | op2 | imm22 |
// |-----------------------------------------------------------------------------------------------|
// | op |a | cond | op2 | disp22 |
// |-----------------------------------------------------------------------------------------------|
//
//
// Instruction format C (op=2|op=3): arithmetic, logical, shift, memory instructions & remaining.
//
// |31 |29 |24 |18 |13|12 |4 0|
// |-----------------------------------------------------------------------------------------------|
// | op | rd | op3 | rs1 |0 | asi | rs2 |
// |-----------------------------------------------------------------------------------------------|
// | op | rd | op3 | rs1 |1 | simm13 |
// |-----------------------------------------------------------------------------------------------|
// | op | rd | op3 | rs1 | opf | rs2 |
// |-----------------------------------------------------------------------------------------------|
//
enum SparcInstructionKind
{
siAnd,
siAndCC,
siAndN,
siAndNCC,
siOr,
siOrCC,
siOrN,
siOrNCC,
siXor,
siXorCC,
siXNor,
siXNorCC,
siSll,
siSrl,
siSra,
siAdd,
siAddCC,
siAddX,
siAddXCC,
siSub,
siSubCC,
siSubX,
siSubXCC,
siUMul,
siUMulCC,
siSMul,
siSMulCC,
siUDiv,
siUDivCC,
siSDiv,
siSDivCC,
siTrap,
siLdSb,
siLdSh,
siLdUb,
siLdUh,
siLd,
siLdd,
siStSb,
siStSh,
siSt,
siStd,
siBranch,
nSparcInstructionKind
};
enum SparcAccessKind
{
saRRR, // insn r[s1],r[s2],r[d]
saRIR, // insn r[s1],imm13,r[d]
saRZR, // insn r[s1],r[g0],r[d]
saZRR, // insn r[g0],r[s2],r[d]
saZIR, // insn r[g0],imm13,r[d]
saZZR, // insn r[g0],r[g0],r[d]
saRRZ, // insn r[s1],r[s2],r[g0]
saRIZ, // insn r[s1],imm13,r[g0]
saRZZ, // insn r[s1],r[g0],r[g0]
nSparcAccessKind
};
#define saRR saRRZ
#define saRI saRIZ
#define saRZ saRZZ
enum SparcConditionKind
{
scA, // always
scN, // never
scNe, // on Not Equal
scE, // on Equal
scG, // on Greater
scLe, // on Less or Equal
scGe, // on Greater or Equal
scL, // on Less
scGu, // on Greater Unsigned
scLeu, // on Less or Equal Unsigned
scCc, // on Carry Clear (Greater than or Equal, Unsigned)
scGeu,
scCs, // on Carry Set (Less than, Unsigned)
scLu,
scPos, // on Positive
scNeg, // on Negative
scVc, // on Overflow Clear
scVs, // on Overflow Set
nSparcConditionKind
};
enum SparcRegisterNumber
{
g0, g1, g2, g3, g4, g5, g6, g7,
o0, o1, o2, o3, o4, o5, sp, o7,
l0, l1, l2, l3, l4, l5, l6, l7,
i0, i1, i2, i3, i4, i5, fp, i7
};
struct SparcConditionInfo
{
SparcConditionKind kind;
uint8 cond;
char *string;
};
struct SparcInstructionInfo
{
SparcInstructionKind kind;
uint8 op;
uint8 op3;
char* string;
};
struct SparcAccessInfo
{
SparcAccessKind kind;
uint8 nConsumer;
uint8 nProducer;
};
extern SparcInstructionInfo siInfo[];
extern SparcAccessInfo saInfo[];
extern SparcConditionInfo scInfo[];
extern char* registerNumberToString[];
extern SparcRegisterNumber colorToRegisterNumber[];
extern uint8 registerNumberToColor[];
class SparcFormatBCond : public InsnUseXDefineYFromPool
{
protected:
SparcInstructionKind kind;
SparcConditionKind cond;
bool a;
ControlNode& target;
public:
SparcFormatBCond(DataNode* inPrimitive, Pool& inPool, ControlNode& t, SparcInstructionKind iKind, SparcConditionKind cKind, bool annul) :
InsnUseXDefineYFromPool(inPrimitive, inPool, 1, 0),
kind(iKind), cond(cKind), a(annul), target(t) {}
virtual void printPretty(FILE* f);
virtual size_t getFormattedSize() {return (a ? 8 : 4);}
virtual void formatToMemory(void* inStart, uint32 inOffset);
};
class SparcBranch : public SparcFormatBCond
{
public:
SparcBranch(DataNode* inPrimitive, Pool& inPool, ControlNode& t, SparcConditionKind cKind, bool annul) :
SparcFormatBCond(inPrimitive, inPool, t, siBranch, cKind, annul) {}
};
class SparcFormatC : public InsnUseXDefineYFromPool
{
protected:
SparcInstructionKind kind;
SparcAccessKind access;
int16 imm13;
public:
SparcFormatC(DataNode* inPrimitive, Pool& inPool, uint8 nConsumer = 0, uint8 nProducer = 0) :
InsnUseXDefineYFromPool(inPrimitive, inPool, nConsumer, nProducer) {}
virtual void printPretty(FILE* f);
virtual size_t getFormattedSize() {return 4;}
virtual void formatToMemory(void* inStart, uint32 /*inOffset*/);
inline SparcRegisterNumber useToRegisterNumber(InstructionUse& use);
inline SparcRegisterNumber defineToRegisterNumber(InstructionDefine& use);
virtual uint8 getRS1();
virtual uint8 getRS2();
virtual uint8 getRD();
};
class SparcInsn : public SparcFormatC
{
public:
SparcInsn(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, int16 constant = 0) :
SparcFormatC(inPrimitive, inPool, saInfo[aKind].nConsumer, saInfo[aKind].nProducer)
{kind = iKind; access = aKind; imm13 = constant;}
virtual InstructionFlags getFlags() const {if (kind == siOr && access == saRZR) return (ifCopy); else return(ifNone);}
};
class SparcTrap : public SparcFormatC
{
protected:
SparcConditionKind cond;
public:
SparcTrap(DataNode* inPrimitive, Pool& inPool, SparcConditionKind cKind, SparcAccessKind aKind, int16 constant = 0) :
SparcFormatC(inPrimitive, inPool, 1, 0), cond(cKind)
{kind = siTrap; access = aKind; imm13 = constant;}
virtual uint8 getRS1() {return g0;}
virtual uint8 getRS2() {return g0;}
virtual uint8 getRD() {return scInfo[cond].cond;}
virtual void printPretty(FILE* f);
};
class SparcCmp : public SparcFormatC
{
public:
SparcCmp(DataNode* inPrimitive, Pool& inPool, SparcAccessKind aKind, int16 constant = 0) :
SparcFormatC(inPrimitive, inPool, saInfo[aKind].nConsumer, 1)
{kind = siSubCC; access = aKind; imm13 = constant;}
};
class SparcLoadStore : public SparcFormatC
{
protected:
bool hasMemoryEdge;
bool isLoad;
bool isLoadC;
public:
SparcLoadStore(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, bool has_mem, bool is_load, bool is_loadC, int16 constant = 0) :
SparcFormatC(inPrimitive, inPool, is_load ? (is_loadC ? 1 : 2) : 3, (is_load && has_mem) ? 2 : 1), hasMemoryEdge(has_mem), isLoad(is_load), isLoadC(is_loadC)
{
kind = iKind; access = aKind; imm13 = constant;
}
virtual void printPretty(FILE* f);
virtual uint8 getRS1();
virtual uint8 getRS2();
virtual uint8 getRD();
};
class SparcLoadC : public SparcLoadStore
{
public:
SparcLoadC(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, int16 constant = 0) :
SparcLoadStore(inPrimitive, inPool, iKind, aKind, false, true, true, constant) {}
};
class SparcLoad : public SparcLoadStore
{
public:
SparcLoad(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, bool memEdge, int16 constant = 0) :
SparcLoadStore(inPrimitive, inPool, iKind, aKind, memEdge, true, false, constant) {}
};
class SparcStore : public SparcLoadStore
{
public:
SparcStore(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, int16 constant = 0) :
SparcLoadStore(inPrimitive, inPool, iKind, aKind, true, false, false, constant) {}
};
inline SparcRegisterNumber SparcFormatC::
useToRegisterNumber(InstructionUse& use)
{
assert(use.isVirtualRegister());
return (colorToRegisterNumber[use.getVirtualRegister().getColor()]);
}
inline SparcRegisterNumber SparcFormatC::
defineToRegisterNumber(InstructionDefine& def)
{
assert(def.isVirtualRegister());
return (colorToRegisterNumber[def.getVirtualRegister().getColor()]);
}
#endif /* _SPARC_INSTRUCTION_H_ */

Просмотреть файл

@ -0,0 +1,591 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "SparcSunOSEmitter.h"
#include "SparcInstruction.h"
#include "ControlNodes.h"
#include "sparc-sunos.nad.burg.h"
#define BINARY_PRIMITIVE_I(inRuleKind, inOp) \
case inRuleKind: \
emit_Insn_I(inPrimitive, inOp); \
break;
#define BINARY_PRIMITIVEI_I(inRuleKind, inOp) \
case inRuleKind: \
emit_InsnI_I(inPrimitive, inOp); \
break;
#define UNDEFINED_RULE(inRuleKind) \
case inRuleKind: \
assert(false); \
break;
#define BINARY_PRIMITIVE_SET(inRuleRoot, inOp) \
BINARY_PRIMITIVE_I(inRuleRoot##_I, inOp); \
UNDEFINED_RULE(inRuleRoot##_L); \
BINARY_PRIMITIVEI_I(inRuleRoot##I_I, inOp); \
UNDEFINED_RULE(inRuleRoot##I_L);
void SparcSunOSEmitter::
emitPrimitive(Primitive& inPrimitive, NamedRule inRule)
{
switch (inRule)
{
case emConst_I:
emit_Const_I(inPrimitive);
break;
case emArg_I:
case emArg_L:
case emArg_F:
case emArg_D:
case emArg_A:
assert(false);
break;
case emResult_M:
case emArg_M:
break;
case emResult_I:
{
VirtualRegister* returnVr;
if (inPrimitive.nthInputIsConstant(0))
{
returnVr = &genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(0).i);
}
else
{
SparcInsn& copyInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siOr, saRZR);
returnVr = &defineTemporary(copyInsn, 0);
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0);
}
returnVr->precolorRegister(registerNumberToColor[o0]);
InsnExternalUse& externalUse = *new(mPool) InsnExternalUse(&inPrimitive);
useTemporaryVR(externalUse, *returnVr, 0);
inPrimitive.setInstructionRoot(&externalUse);
}
break;
case emIfLt:
emit_B(inPrimitive, scL);
break;
case emIfULt:
emit_B(inPrimitive, scLu);
break;
case emIfEq:
case emIfUEq:
emit_B(inPrimitive, scE);
break;
case emIfLe:
emit_B(inPrimitive, scLe);
break;
case emIfULe:
emit_B(inPrimitive, scLeu);
break;
case emIfGt:
emit_B(inPrimitive, scG);
break;
case emIfUGt:
emit_B(inPrimitive, scGu);
break;
case emIfLgt:
case emIfNe:
emit_B(inPrimitive, scNe);
break;
case emIfGe:
emit_B(inPrimitive, scGe);
break;
case emIfUGe:
emit_B(inPrimitive, scGeu);
break;
case emIfOrd:
case emIfUnord:
assert(false); // Shouldn't happen with int edges...
break;
BINARY_PRIMITIVE_SET(emAnd, siAnd);
BINARY_PRIMITIVE_SET(emOr, siOr );
BINARY_PRIMITIVE_SET(emXor, siXor);
BINARY_PRIMITIVE_SET(emAdd, siAdd);
case emAdd_A:
emit_Insn_I(inPrimitive, siAdd);
break;
case emAddI_A:
emit_InsnI_I(inPrimitive, siAdd);
break;
BINARY_PRIMITIVE_SET(emMul, siSMul);
case emDivI_I:
emit_DivI_I(inPrimitive);
break;
case emModE_I:
emit_ModE_I(inPrimitive);
break;
case emShlI_I:
emit_InsnI_I(inPrimitive, siSll);
break;
case emChkNull:
emit_ChkNull(inPrimitive);
break;
case emLimitR:
emit_LimitR(inPrimitive);
break;
case emLimit:
emit_Limit(inPrimitive);
break;
case emLdC_IRegisterIndirect:
emit_LdC_IRegisterIndirect(inPrimitive);
break;
case emLd_IRegisterIndirect:
emit_Ld_IRegisterIndirect(inPrimitive);
break;
case emLdC_I:
fprintf(stdout, "*** should emit emLdC_I\n");
//genLoadIZero(inPrimitive, pfConstant);
break;
case emLd_I:
fprintf(stdout, "*** should emit emLd_I\n");
//genLoadIZero(inPrimitive, 0);
break;
case emSt_I:
fprintf(stdout, "*** should emit emSt_I\n");
//{
//StoreNoUpdateD& newInsn = *new(mPool) StoreNoUpdateD(&inPrimitive, mPool, dfStw, 0, 0);
//newInsn.standardUseDefine(*this);
//}
break;
case emStI_I:
fprintf(stdout, "*** should emit emStI_I\n");
//emit_StI_I(inPrimitive);
break;
case emStI_IRegisterIndirect:
emit_StI_IRegisterIndirect(inPrimitive);
break;
case emSt_IRegisterIndirect:
emit_St_IRegisterIndirect(inPrimitive);
break;
case emCallI_I:
case emCallI_L:
case emCallI_F:
case emCallI_D:
case emCallI_P:
fprintf(stdout, "*** should emit emCallI_P\n");
//emit_Call(inPrimitive);
break;
case emCmp_I:
emit_Cmp_I(inPrimitive);
break;
case emCmpI_I:
emit_CmpI_I(inPrimitive);
break;
default:
//assert(false)
break;
}
}
void SparcSunOSEmitter::
emit_Const_I(Primitive& inPrimitive)
{
int32 constI = (*static_cast<const PrimConst *>(&inPrimitive)).value.i;
if ((constI >= -4096) && (constI <= 4095))
{
SparcInsn& newInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siOr, constI ? saZIR : saZZR, constI & 0x1fff);
defineProducer(inPrimitive, newInsn, 0);
}
else if ((constI & 0x1fff) == 0)
{
// FIXME
assert(0);
}
else
{
// FIXME
assert(0);
}
}
void SparcSunOSEmitter::
emit_InsnI_I(Primitive& inPrimitive, SparcInstructionKind kind)
{
int32 constI = inPrimitive.nthInputConstant(1).i;
if ((constI >= -4096) && (constI <= 4095))
{
SparcInsn& newInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, kind, constI ? saRIR : saRZR, constI & 0x1fff);
newInsn.standardUseDefine(*this);
}
else
{
assert(0);
}
}
void SparcSunOSEmitter::
emit_Insn_I(Primitive& inPrimitive, SparcInstructionKind kind)
{
SparcInsn& newInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, kind, saRRR);
newInsn.standardUseDefine(*this);
}
void SparcSunOSEmitter::
emit_Cmp_I(Primitive& inPrimitive)
{
SparcCmp& newInsn = *new(mPool) SparcCmp(&inPrimitive, mPool, saRR);
newInsn.standardUseDefine(*this);
}
void SparcSunOSEmitter::
emit_CmpI_I(Primitive& inPrimitive)
{
int32 constI = inPrimitive.nthInputConstant(1).i;
if ((constI >= -4096) && (constI <= 4095))
{
SparcCmp& newInsn = *new(mPool) SparcCmp(&inPrimitive, mPool, constI ? saRI : saRZ, constI & 0x1fff);
newInsn.standardUseDefine(*this);
}
else
{
assert(0);
}
}
void SparcSunOSEmitter::
emit_B(Primitive& inPrimitive, SparcConditionKind cond)
{
ControlIf& controlIf = ControlIf::cast(*inPrimitive.getContainer());
SparcBranch& newInsn = *new(mPool) SparcBranch(&inPrimitive, mPool, *(controlIf.getTrueIfEdge().target), cond, true);
newInsn.standardUseDefine(*this);
}
Instruction& SparcSunOSEmitter::
emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget)
{
SparcBranch& newInsn = *new(mPool) SparcBranch(&inDataNode, mPool, inTarget, scA, true);
return (newInsn);
}
void SparcSunOSEmitter::
emitArguments(ControlBegin& inBeginNode)
{
uint32 curParamWords; // number of words of argument space used
uint32 curFloatingPointArg; // number of floating point arguments
InsnExternalDefine& defineInsn = *new(mPool) InsnExternalDefine(&inBeginNode.arguments[0], mPool, inBeginNode.nArguments * 2);
uint32 curArgIdx; // current index into the arguments in the ControlBegin
curParamWords = 0;
curFloatingPointArg = 0;
for (curArgIdx = 0; curArgIdx < inBeginNode.nArguments && curParamWords < 6; curArgIdx++)
{
PrimArg& curArg = inBeginNode.arguments[curArgIdx];
switch (curArg.getOperation())
{
case poArg_I:
case poArg_A:
{
SparcInsn& copyInsn = *new(mPool) SparcInsn(&curArg, mPool, siOr, saRZR);
// hook up this vr to the external define FIX-ME
VirtualRegister& inputVr = defineTemporary(defineInsn, curArgIdx);
inputVr.precolorRegister(registerNumberToColor[i0+curParamWords]);
// emit the copy
useTemporaryVR(copyInsn, inputVr, 0);
defineProducer(curArg, copyInsn, 0);
curParamWords++;
break;
}
case poArg_L:
assert(false);
case poArg_F:
assert(false);
case poArg_D:
assert(false);
break;
case poArg_M:
break;
default:
assert(false);
break;
}
}
// FIXME: emit the load for the arguments on the stack
// 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
}
Instruction& SparcSunOSEmitter::
emitCopy(DataNode& inDataNode, VirtualRegister& fromVr, VirtualRegister& toVr)
{
SparcInsn& newInsn = *new(mPool) SparcInsn(&inDataNode, mPool, siOr, saRZR);
newInsn.addUse(0, fromVr);
newInsn.addDefine(0, toVr);
#if DEBUG
toVr.setDefineInstruction(newInsn);
#endif
return (newInsn);
}
void SparcSunOSEmitter::
emit_DivI_I(Primitive& inPrimitive)
{
Value& immediate = inPrimitive.nthInputConstant(1);
if(isPowerOfTwo(immediate.i))
{
uint8 shiftBy = 31 - leadingZeros(immediate.i);
SparcInsn& shiftRightL = *new(mPool) SparcInsn(&inPrimitive, mPool, siSrl, saRIR, 31);
useProducer(inPrimitive.nthInputVariable(0), shiftRightL, 0);
VirtualRegister& tempVr = defineTemporary(shiftRightL, 0);
inPrimitive.setInstructionRoot(&shiftRightL);
SparcInsn& addInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siAdd, saRRR);
useProducer(inPrimitive.nthInputVariable(0), addInsn, 0);
useTemporaryVR(addInsn, tempVr, 1);
redefineTemporary(addInsn, tempVr, 0);
SparcInsn& shiftRight = *new(mPool) SparcInsn(&inPrimitive, mPool, siSra, saRIR, shiftBy);
useTemporaryVR(shiftRight, tempVr, 0);
defineProducer(inPrimitive, shiftRight, 0);
}
else
// FIXME: check 0
emit_InsnI_I(inPrimitive, siSDiv);
}
void SparcSunOSEmitter::
emit_ModE_I(Primitive& inPrimitive)
{
// Check the divisor != 0
SparcCmp& cmpInsn = *new(mPool) SparcCmp(&inPrimitive, mPool, saRZ);
useProducer(inPrimitive.nthInputVariable(1), cmpInsn, 0);
cmpInsn.addDefine(0, udCond);
SparcTrap& trapInsn = *new(mPool) SparcTrap(&inPrimitive, mPool, scE, saRRR /* FIXME */);
trapInsn.addUse(0, udCond);
trapInsn.getInstructionUseBegin()->setDefiningInstruction(cmpInsn);
inPrimitive.setInstructionRoot(&trapInsn);
SparcInsn& divInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siSDiv, saRRR);
useProducer(inPrimitive.nthInputVariable(0), divInsn, 0);
useProducer(inPrimitive.nthInputVariable(1), divInsn, 1);
VirtualRegister& tempVr = defineTemporary(divInsn, 0);
SparcInsn& mullInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siSMul, saRRR);
useProducer(inPrimitive.nthInputVariable(1), mullInsn, 1);
useTemporaryVR(mullInsn, tempVr, 0);
redefineTemporary(mullInsn, tempVr, 0);
SparcInsn& subInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siSub, saRRR);
useTemporaryVR(subInsn, tempVr, 0);
useProducer(inPrimitive.nthInputVariable(0), subInsn, 1);
defineProducer(inPrimitive, subInsn, 0);
}
void SparcSunOSEmitter::
emit_ChkNull(Primitive& inPrimitive)
{
SparcCmp& cmpInsn = *new(mPool) SparcCmp(&inPrimitive, mPool, saRZ);
useProducer(inPrimitive.nthInputVariable(0), cmpInsn, 0);
cmpInsn.addDefine(0, udCond);
SparcTrap& trapInsn = *new(mPool) SparcTrap(&inPrimitive, mPool, scE, saRRR /* FIXME */);
trapInsn.addUse(0, udCond);
trapInsn.getInstructionUseBegin()->setDefiningInstruction(cmpInsn);
inPrimitive.setInstructionRoot(&trapInsn);
}
void SparcSunOSEmitter::
emit_LimitR(Primitive& inPrimitive)
{
int32 constI = inPrimitive.nthInputConstant(0).i;
if ((constI >= -4096) && (constI <= 4095))
{
SparcCmp& cmpInsn = *new(mPool) SparcCmp(&inPrimitive, mPool, constI ? saRI : saRZ, constI & 0x1fff);
useProducer(inPrimitive.nthInputVariable(1), cmpInsn, 0);
cmpInsn.addDefine(0, udCond);
SparcTrap& trapInsn = *new(mPool) SparcTrap(&inPrimitive, mPool, scLe, saRRR /* FIXME */);
trapInsn.addUse(0, udCond);
trapInsn.getInstructionUseBegin()->setDefiningInstruction(cmpInsn);
inPrimitive.setInstructionRoot(&trapInsn);
}
else
{
assert(0);
}
}
void SparcSunOSEmitter::
emit_Limit(Primitive& inPrimitive)
{
SparcCmp& cmpInsn = *new(mPool) SparcCmp(&inPrimitive, mPool, saRR);
useProducer(inPrimitive.nthInputVariable(0), cmpInsn, 0);
useProducer(inPrimitive.nthInputVariable(1), cmpInsn, 1);
cmpInsn.addDefine(0, udCond);
SparcTrap& trapInsn = *new(mPool) SparcTrap(&inPrimitive, mPool, scGe, saRRR /* FIXME */);
trapInsn.addUse(0, udCond);
trapInsn.getInstructionUseBegin()->setDefiningInstruction(cmpInsn);
inPrimitive.setInstructionRoot(&trapInsn);
}
void SparcSunOSEmitter::
emit_LdC_IRegisterIndirect(Primitive& inPrimitive)
{
DataNode& immSource = inPrimitive.nthInput(0).getProducer().getNode();
int32 constI = immSource.nthInputConstant(1).i;
if ((constI >= -4096) && (constI <= 4095))
{
SparcLoadC& newInsn = *new(mPool) SparcLoadC(&inPrimitive, mPool, siLd, saRIR, constI);
useProducer(immSource.nthInputVariable(0), newInsn, 0);
defineProducer(inPrimitive, newInsn, 0);
}
else
{
assert(false);
}
}
void SparcSunOSEmitter::
emit_Ld_IRegisterIndirect(Primitive& inPrimitive)
{
DataNode& immSource = inPrimitive.nthInput(1).getProducer().getNode();
int32 constI = immSource.nthInputConstant(1).i;
if ((constI >= -4096) && (constI <= 4095))
{
SparcLoad& newInsn = *new(mPool) SparcLoad(&inPrimitive, mPool, siLd, saRIR, false, constI);
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);
}
}
void SparcSunOSEmitter::
emit_StI_IRegisterIndirect(Primitive& inPrimitive)
{
SparcStore* storeInsn;
// load the constant to be stored into constVr
VirtualRegister& constVr = genLoadConstant(inPrimitive, inPrimitive.nthInputConstant(2).i);
// grab the immediate value from the incoming poAddA_I
DataNode& addrSource = inPrimitive.nthInput(1).getProducer().getNode();
int32 offset = addrSource.nthInputConstant(1).i;
if ((offset >= -4096) && (offset <= 4095))
{
storeInsn = new(mPool) SparcStore(&inPrimitive, mPool, siSt, saRIR, offset);
useProducer(addrSource.nthInputVariable(0), *storeInsn, 1);
}
else
{
assert(false);
}
useProducer(inPrimitive.nthInputVariable(0), *storeInsn, 0); // <- store
useTemporaryVR(*storeInsn, constVr, 2); // <- value
defineProducer(inPrimitive, *storeInsn, 0); // -> store
}
void SparcSunOSEmitter::
emit_St_IRegisterIndirect(Primitive& inPrimitive)
{
DataNode& addrSource = inPrimitive.nthInput(1).getProducer().getNode();
int32 offset = addrSource.nthInputConstant(1).i;
if ((offset >= -4096) && (offset <= 4095))
{
SparcStore& storeInsn = *new(mPool) SparcStore(&inPrimitive, mPool, siSt, saRIR, 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
}
else
{
assert(false);
}
}
VirtualRegister& SparcSunOSEmitter::
genLoadConstant(DataNode& inPrimitive, int32 constI)
{
if ((constI >= -4096) && (constI <= 4095))
{
SparcInsn& newInsn = *new(mPool) SparcInsn(&inPrimitive, mPool, siOr, constI ? saZIR : saZZR, constI & 0x1fff);
VirtualRegister& constantVr = defineTemporary(newInsn, 0);
return constantVr;
}
else if ((constI & 0x1fff) == 0)
{
// FIXME
assert(0);
}
else
{
// FIXME
assert(0);
}
}
uint32 SparcSunOSEmitter::
getPrologSize() const
{
return 4;
}
void SparcSunOSEmitter::
formatPrologToMemory(void* inWhere)
{
*(uint32*) inWhere = 0x9de3bf90; // save %sp,-112,%sp
}
uint32 SparcSunOSEmitter::
getEpilogSize() const
{
return 8;
}
void SparcSunOSEmitter::
formatEpilogToMemory(void* inWhere)
{
((uint32*) inWhere)[0] = 0x81c7e008; // ret
((uint32*) inWhere)[1] = 0x81e80000; // restore %g0,%g0,%g0
}

Просмотреть файл

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPARC_SUNOS_EMITTER_H_
#define _SPARC_SUNOS_EMITTER_H_
#include "InstructionEmitter.h"
#include "SparcInstruction.h"
#include "VirtualRegister.h"
class PrimArg;
class Pool;
class SparcSunOSEmitter : public InstructionEmitter
{
public:
SparcSunOSEmitter(Pool& inPool, VirtualRegisterManager& vrMan) : InstructionEmitter(inPool, vrMan) {}
virtual void emitPrimitive(Primitive& inPrimitive, NamedRule inRule);
virtual uint32 getPrologSize() const;
virtual void formatPrologToMemory(void* inWhere);
virtual uint32 getEpilogSize() const;
virtual void formatEpilogToMemory(void* inWhere);
virtual void emitArguments(ControlBegin& inBeginNode);
virtual void emitArgument(PrimArg& /*inArguments*/, const uint /*inArgumentIndex*/) {}
virtual Instruction& emitCopy(DataNode& inDataNode, VirtualRegister& fromVr, VirtualRegister& toVr);
virtual Instruction& emitLoad(DataNode& /*inDataNode*/, VirtualRegister& /*loadedRegister*/, VirtualRegister& /*stackRegister*/) {}
virtual Instruction& emitStore(DataNode& /*inDataNode*/, VirtualRegister& /*storedRegister*/, VirtualRegister& /*stackRegister*/) {};
virtual Instruction& emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget);
void emit_Insn_I(Primitive& inPrimitive, SparcInstructionKind kind);
void emit_InsnI_I(Primitive& inPrimitive, SparcInstructionKind kind);
void emit_Const_I(Primitive& inPrimitive);
void emit_Cmp_I(Primitive& inPrimitive);
void emit_CmpI_I(Primitive& inPrimitive);
void emit_B(Primitive& inPrimitive, SparcConditionKind kind);
void emit_ModE_I(Primitive& inPrimitive);
void emit_DivI_I(Primitive& inPrimitive);
void emit_ChkNull(Primitive& inPrimitive);
void emit_LimitR(Primitive& inPrimitive);
void emit_Limit(Primitive& inPrimitive);
void emit_LdC_IRegisterIndirect(Primitive& inPrimitive);
void emit_Ld_IRegisterIndirect(Primitive& inPrimitive);
void emit_StI_IRegisterIndirect(Primitive& inPrimitive);
void emit_St_IRegisterIndirect(Primitive& inPrimitive);
VirtualRegister& genLoadConstant(DataNode& inPrimitive, int32 inConstant);
};
#endif /* _SPARC_SUNOS_EMITTER_H_ */

Просмотреть файл

@ -0,0 +1,441 @@
%top
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Burg.h"
%
%terminals
%
%startsymbols
Control
Result
Exception
Store
Vcond
Vint
Vlong
Vfloat
Vdouble
Vptr
Cint
Clong
Cfloat
Cdouble
Cptr
%
%grammar
Vint: coReg_I $1 $
Vlong: coReg_L $1 $
Vfloat: coReg_F $1 $
Vdouble: coReg_D $1 $
Vptr: coReg_A $1 $
Vcond: coReg_C $1 $
Store: coReg_M $1 $
Cint: coReg_I $1 $
Clong: coReg_L $1 $
Cfloat: coReg_F $1 $
Cdouble: coReg_D $1 $
Cptr: coReg_A $1 $
Vint: poConst_I $1 $emConst_I
Vlong: poConst_L $1 $emConst_L
Vfloat: poConst_F $1 $emConst_F
Vdouble: poConst_D $1 $emConst_D
Vptr: poConst_A $1 $emConst_A
Vcond: poConst_C $1 $emConst_C
Store: poBreak(Store) $1 $emBreak
Vint: poArg_I $1 $emArg_I
Vlong: poArg_L $1 $emArg_L
Vfloat: poArg_F $1 $emArg_F
Vdouble: poArg_D $1 $emArg_D
Vptr: poArg_A $1 $emArg_A
Store: poArg_M $1 $emArg_M
Result: poResult_I(Vint) $1 $emResult_I
Result: poResult_L(Vlong) $1 $emResult_L
Result: poResult_F(Vfloat) $1 $emResult_F
Result: poResult_D(Vdouble) $1 $emResult_D
Result: poResult_A(Vptr) $1 $emResult_A
// (not used): poResult_C(Acond) $1 $emResult_C
Result: poResult_M(Store) $1 $emResult_M
Control: poIfLt(Vcond) $1 $emIfLt
Control: poIfEq(Vcond) $1 $emIfEq
Control: poIfLe(Vcond) $1 $emIfLe
Control: poIfGt(Vcond) $1 $emIfGt
Control: poIfLgt(Vcond) $1 $emIfLgt
Control: poIfGe(Vcond) $1 $emIfGe
Control: poIfOrd(Vcond) $1 $emIfOrd
Control: poIfUnord(Vcond) $1 $emIfUnord
Control: poIfULt(Vcond) $1 $emIfULt
Control: poIfUEq(Vcond) $1 $emIfUEq
Control: poIfULe(Vcond) $1 $emIfULe
Control: poIfUGt(Vcond) $1 $emIfUGt
Control: poIfNe(Vcond) $1 $emIfNe
Control: poIfUGe(Vcond) $1 $emIfUGe
Control: poSwitch(Vint) $1 $emSwitch
Vint: poAnd_I(Vint, Vint) $1 $emAnd_I
Vlong: poAnd_L(Vlong, Vlong) $1 $emAnd_L
Vint: poAndI_I(Vint, Cint) $1 $emAndI_I
Vlong: poAndI_L(Vlong, Clong) $1 $emAndI_L
Vint: poOr_I(Vint, Vint) $1 $emOr_I
Vlong: poOr_L(Vlong, Vlong) $1 $emOr_L
Vint: poOrI_I(Vint, Cint) $1 $emOrI_I
Vlong: poOrI_L(Vlong, Clong) $1 $emOrI_L
Vint: poXor_I(Vint, Vint) $1 $emXor_I
Vlong: poXor_L(Vlong, Vlong) $1 $emXor_L
Vint: poXorI_I(Vint, Cint) $1 $emXorI_I
Vlong: poXorI_L(Vlong, Clong) $1 $emXorI_L
Vint: poAdd_I(Vint, Vint) $1 $emAdd_I
Vlong: poAdd_L(Vlong, Vlong) $1 $emAdd_L
Vptr: poAdd_A(Vptr, Vint) $1 $emAdd_A
Vptr: poAddU_A(Vptr, Vint) $1 $emAddU_A
Vint: poAddI_I(Vint, Cint) $1 $emAddI_I
Vlong: poAddI_L(Vlong, Clong) $1 $emAddI_L
Vptr: poAddI_A(Vptr, Cint) $1 $emAddI_A
Vptr: poAddR_A(Cptr, Vint) $1 $emAddR_A
Vptr: poAddRU_A(Cptr, Vint) $1 $emAddRU_A
Vint: poSub_I(Vint, Vint) $1 $emSub_I
Vlong: poSub_L(Vlong, Vlong) $1 $emSub_L
Vptr: poSub_A(Vptr, Vint) $1 $emSub_A
Vptr: poSubU_A(Vptr, Vint) $1 $emSubU_A
Vint: poSubR_I(Cint, Vint) $1 $emSubR_I
Vlong: poSubR_L(Clong, Vlong) $1 $emSubR_L
Vptr: poSubR_A(Cptr, Vint) $1 $emSubR_A
Vptr: poSubUR_A(Cptr, Vint) $1 $emSubUR_A
Vint: poSubA_I(Vptr, Vptr) $1 $emSubA_I
Vint: poSubAI_I(Vptr, Cptr) $1 $emSubAI_I
Vint: poSubAR_I(Cptr, Vptr) $1 $emSubAR_I
Vint: poMul_I(Vint, Vint) $1 $emMul_I
Vlong: poMul_L(Vlong, Vlong) $1 $emMul_L
Vint: poMulI_I(Vint, Cint) $1 $emMulI_I
Vlong: poMulI_L(Vlong, Clong) $1 $emMulI_L
Vint: poDivI_I(Vint, Cint) $1 $emDivI_I
Vint: poModE_I(Vint, Vint) $1 $emModE_I
Vint: poShl_I(Vint, Vint) $1 $emShl_I
Vlong: poShl_L(Vlong, Vint) $1 $emShl_L
Vint: poShlI_I(Vint, Cint) $1 $emShlI_I
Vlong: poShlI_L(Vlong, Cint) $1 $emShlI_L
Vint: poShlR_I(Cint, Vint) $1 $emShlR_I
Vlong: poShlR_L(Clong, Vint) $1 $emShlR_L
Vint: poShr_I(Vint, Vint) $1 $emShr_I
Vlong: poShr_L(Vlong, Vint) $1 $emShr_L
Vint: poShrI_I(Vint, Cint) $1 $emShrI_I
Vlong: poShrI_L(Vlong, Cint) $1 $emShrI_L
Vint: poShrR_I(Cint, Vint) $1 $emShrR_I
Vlong: poShrR_L(Clong, Vint) $1 $emShrR_L
Vint: poShrU_I(Vint, Vint) $1 $emShrU_I
Vlong: poShrU_L(Vlong, Vint) $1 $emShrU_L
Vint: poShrUI_I(Vint, Cint) $1 $emShrUI_I
Vlong: poShrUI_L(Vlong, Cint) $1 $emShrUI_L
Vint: poShrUR_I(Cint, Vint) $1 $emShrUR_I
Vlong: poShrUR_L(Clong, Vint) $1 $emShrUR_L
Vint: poExt_I(Vint, Cint) $1 $emExt_I
Vlong: poExt_L(Vlong, Cint) $1 $emExt_L
Vfloat: poFAdd_F(Vfloat, Vfloat) $1 $emFAdd_F
Vdouble: poFAdd_D(Vdouble, Vdouble) $1 $emFAdd_D
Vfloat: poFAddI_F(Vfloat, Cfloat) $1 $emFAddI_F
Vdouble: poFAddI_D(Vdouble, Cdouble) $1 $emFAddI_D
Vfloat: poFSub_F(Vfloat, Vfloat) $1 $emFSub_F
Vdouble: poFSub_D(Vdouble, Vdouble) $1 $emFSub_D
Vfloat: poFSubR_F(Cfloat, Vfloat) $1 $emFSubR_F
Vdouble: poFSubR_D(Cdouble, Vdouble) $1 $emFSubR_D
Vfloat: poFMul_F(Vfloat, Vfloat) $1 $emFMul_F
Vdouble: poFMul_D(Vdouble, Vdouble) $1 $emFMul_D
Vfloat: poFMulI_F(Vfloat, Cfloat) $1 $emFMulI_F
Vdouble: poFMulI_D(Vdouble, Cdouble) $1 $emFMulI_D
Vfloat: poFDiv_F(Vfloat, Vfloat) $1 $emFDiv_F
Vdouble: poFDiv_D(Vdouble, Vdouble) $1 $emFDiv_D
Vfloat: poFDivI_F(Vfloat, Cfloat) $1 $emFDivI_F
Vdouble: poFDivI_D(Vdouble, Cdouble) $1 $emFDivI_D
Vfloat: poFDivR_F(Cfloat, Vfloat) $1 $emFDivR_F
Vdouble: poFDivR_D(Cdouble, Vdouble) $1 $emFDivR_D
Vfloat: poFRem_F(Vfloat, Vfloat) $1 $emFRem_F
Vdouble: poFRem_D(Vdouble, Vdouble) $1 $emFRem_D
Vfloat: poFRemI_F(Vfloat, Cfloat) $1 $emFRemI_F
Vdouble: poFRemI_D(Vdouble, Cdouble) $1 $emFRemI_D
Vfloat: poFRemR_F(Cfloat, Vfloat) $1 $emFRemR_F
Vdouble: poFRemR_D(Cdouble, Vdouble) $1 $emFRemR_D
Vint: poConvI_L(Vlong) $1 $emConvI_L
Vlong: poConvL_I(Vint) $1 $emConvL_I
Vint: poFConvI_F(Vfloat) $1 $emFConvI_F
Vint: poFConvI_D(Vdouble) $1 $emFConvI_D
Vlong: poFConvL_F(Vfloat) $1 $emFConvL_F
Vlong: poFConvL_D(Vdouble) $1 $emFConvL_D
Vfloat: poFConvF_I(Vint) $1 $emFConvF_I
Vfloat: poFConvF_L(Vlong) $1 $emFConvF_L
Vfloat: poFConvF_D(Vdouble) $1 $emFConvF_D
Vdouble: poFConvD_I(Vint) $1 $emFConvD_I
Vdouble: poFConvD_L(Vlong) $1 $emFConvD_L
Vdouble: poFConvD_F(Vfloat) $1 $emFConvD_F
Vcond: poCmp_I(Vint, Vint) $1 $emCmp_I
Vcond: poCmp_L(Vlong, Vlong) $1 $emCmp_L
Vcond: poCmpI_I(Vint, Cint) $1 $emCmpI_I
Vcond: poCmpI_L(Vlong, Clong) $1 $emCmpI_L
Vcond: poCmpU_I(Vint, Vint) $1 $emCmpU_I
Vcond: poCmpU_L(Vlong, Vlong) $1 $emCmpU_L
Vcond: poCmpU_A(Vptr, Vptr) $1 $emCmpU_A
Vcond: poCmpUI_I(Vint, Cint) $1 $emCmpUI_I
Vcond: poCmpUI_L(Vlong, Clong) $1 $emCmpUI_L
Vcond: poCmpUI_A(Vptr, Cptr) $1 $emCmpUI_A
Vcond: poFCmp_F(Vfloat, Vfloat) $1 $emFCmp_F
Vcond: poFCmp_D(Vdouble, Vdouble) $1 $emFCmp_D
Vcond: poFCmpI_F(Vfloat, Cfloat) $1 $emFCmpI_F
Vcond: poFCmpI_D(Vdouble, Cdouble) $1 $emFCmpI_D
Vint: poLt_I(Vcond) $1 $emLt_I
Vint: poEq_I(Vcond) $1 $emEq_I
Vint: poLe_I(Vcond) $1 $emLe_I
Vint: poGt_I(Vcond) $1 $emGt_I
Vint: poLgt_I(Vcond) $1 $emLgt_I
Vint: poGe_I(Vcond) $1 $emGe_I
Vint: poOrd_I(Vcond) $1 $emOrd_I
Vint: poUnord_I(Vcond) $1 $emUnord_I
Vint: poULt_I(Vcond) $1 $emULt_I
Vint: poUEq_I(Vcond) $1 $emUEq_I
Vint: poULe_I(Vcond) $1 $emULe_I
Vint: poUGt_I(Vcond) $1 $emUGt_I
Vint: poNe_I(Vcond) $1 $emNe_I
Vint: poUGe_I(Vcond) $1 $emUGe_I
Vint: poCatL_I(Vcond) $1 $emCatL_I
Vint: poCatG_I(Vcond) $1 $emCatG_I
Vint: poCatCL_I(Vcond) $1 $emCatCL_I
Vint: poCatCG_I(Vcond) $1 $emCatCG_I
Exception: poChkNull(Vptr) $1 $emChkNull
Exception: poLimit(Vint, Vint) $1 $emLimit
Exception: poLimitI(Vint, Cint) $1 $emLimitI
Exception: poLimitR(Cint, Vint) $1 $emLimitR
Vint: poLd_I(Vptr) $1 $emLd_I
Vlong: poLd_L(Vptr) $1 $emLd_L
Vfloat: poLd_F(Vptr) $1 $emLd_F
Vdouble: poLd_D(Vptr) $1 $emLd_D
Vptr: poLd_A(Vptr) $1 $emLd_A
Vint: poLdE_I(Cptr) $1 $emLdE_I
Vlong: poLdE_L(Cptr) $1 $emLdE_L
Vfloat: poLdE_F(Cptr) $1 $emLdE_F
Vdouble: poLdE_D(Cptr) $1 $emLdE_D
Vptr: poLdE_A(Cptr) $1 $emLdE_A
Vint: poLdG_I(Cptr) $1 $emLdG_I
Vlong: poLdG_L(Cptr) $1 $emLdG_L
Vfloat: poLdG_F(Cptr) $1 $emLdG_F
Vdouble: poLdG_D(Cptr) $1 $emLdG_D
Vptr: poLdG_A(Cptr) $1 $emLdG_A
Vint: poLdS_B(Vptr) $1 $emLdS_B
Vint: poLdS_H(Vptr) $1 $emLdS_H
Vint: poLdSE_B(Cptr) $1 $emLdSE_B
Vint: poLdSE_H(Cptr) $1 $emLdSE_H
Vint: poLdSG_B(Cptr) $1 $emLdSG_B
Vint: poLdSG_H(Cptr) $1 $emLdSG_H
Vint: poLdU_B(Vptr) $1 $emLdU_B
Vint: poLdU_H(Vptr) $1 $emLdU_H
Vint: poLdUE_B(Cptr) $1 $emLdUE_B
Vint: poLdUE_H(Cptr) $1 $emLdUE_H
Vint: poLdUG_B(Cptr) $1 $emLdUG_B
Vint: poLdUG_H(Cptr) $1 $emLdUG_H
Vint: poLdV_I(Vptr) $1 $emLdV_I
Vlong: poLdV_L(Vptr) $1 $emLdV_L
Vfloat: poLdV_F(Vptr) $1 $emLdV_F
Vdouble: poLdV_D(Vptr) $1 $emLdV_D
Vptr: poLdV_A(Vptr) $1 $emLdV_A
Vint: poLdVE_I(Cptr) $1 $emLdVE_I
Vlong: poLdVE_L(Cptr) $1 $emLdVE_L
Vfloat: poLdVE_F(Cptr) $1 $emLdVE_F
Vdouble: poLdVE_D(Cptr) $1 $emLdVE_D
Vptr: poLdVE_A(Cptr) $1 $emLdVE_A
Vint: poLdVG_I(Cptr) $1 $emLdVG_I
Vlong: poLdVG_L(Cptr) $1 $emLdVG_L
Vfloat: poLdVG_F(Cptr) $1 $emLdVG_F
Vdouble: poLdVG_D(Cptr) $1 $emLdVG_D
Vptr: poLdVG_A(Cptr) $1 $emLdVG_A
Vint: poLdVS_B(Vptr) $1 $emLdVS_B
Vint: poLdVS_H(Vptr) $1 $emLdVS_H
Vint: poLdVSE_B(Cptr) $1 $emLdVSE_B
Vint: poLdVSE_H(Cptr) $1 $emLdVSE_H
Vint: poLdVSG_B(Cptr) $1 $emLdVSG_B
Vint: poLdVSG_H(Cptr) $1 $emLdVSG_H
Vint: poLdVU_B(Vptr) $1 $emLdVU_B
Vint: poLdVU_H(Vptr) $1 $emLdVU_H
Vint: poLdVUE_B(Cptr) $1 $emLdVUE_B
Vint: poLdVUE_H(Cptr) $1 $emLdVUE_H
Vint: poLdVUG_B(Cptr) $1 $emLdVUG_B
Vint: poLdVUG_H(Cptr) $1 $emLdVUG_H
Vint: poLdC_I(Vptr) $1 $emLdC_I
Vint: poLdC_L(Vptr) $1 $emLdC_L
Vint: poLdC_F(Vptr) $1 $emLdC_F
Vint: poLdC_D(Vptr) $1 $emLdC_D
Vint: poLdC_A(Vptr) $1 $emLdC_A
Vint: poLdCE_I(Vptr) $1 $emLdCE_I
Vint: poLdCE_L(Vptr) $1 $emLdCE_L
Vint: poLdCE_F(Vptr) $1 $emLdCE_F
Vint: poLdCE_D(Vptr) $1 $emLdCE_D
Vint: poLdCE_A(Vptr) $1 $emLdCE_A
Vint: poLdC_I(poAddI_A(Vptr, Cint)) $0 $emLdC_IRegisterIndirect
Vint: poLd_I(poAddI_A(Vptr, Cint)) $0 $emLd_IRegisterIndirect
// poLdCG_I = 257, // Load constant global *Cptr -> Vint (not used)
// poLdCG_L = 258, // Load constant global *Cptr -> Vlong (not used)
// poLdCG_F = 259, // Load constant global *Cptr -> Vfloat (not used)
// poLdCG_D = 260, // Load constant global *Cptr -> Vdouble (not used)
// poLdCG_A = 261, // Load constant global *Cptr -> Vptr (not used)
Vint: poLdCS_B(Vptr) $1 $emLdCS_B
Vint: poLdCS_H(Vptr) $1 $emLdCS_H
Vint: poLdCSE_B(Cptr) $1 $emLdCSE_B
Vint: poLdCSE_H(Cptr) $1 $emLdCSE_H
//Vint (not used): poLdCSG_B(Cptr) $1 $emLdCSG_B
//Vint (not used): poLdCSG_H(Cptr) $1 $emLdCSG_H
Vint: poLdCU_B(Vptr) $1 $emLdCU_B
Vint: poLdCU_H(Vptr) $1 $emLdCU_H
Vint: poLdCUE_B(Cptr) $1 $emLdCUE_B
Vint: poLdCUE_H(Cptr) $1 $emLdCUE_H
//Vint (not used): poLdCUG_B(Cptr) $1 $emLdCUG_B
//Vint (not used): poLdCUG_H(Cptr) $1 $emLdCUG_H
Store: poSt_B(Vptr, Vint) $1 $emSt_B
Store: poSt_H(Vptr, Vint) $1 $emSt_H
Store: poSt_I(Vptr, Vint) $1 $emSt_I
Store: poSt_L(Vptr, Vlong) $1 $emSt_L
Store: poSt_F(Vptr, Vfloat) $1 $emSt_F
Store: poSt_D(Vptr, Vdouble) $1 $emSt_D
Store: poSt_A(Vptr, Vptr) $1 $emSt_A
Store: poStI_B(Vptr, Cint) $1 $emStI_B
Store: poStI_H(Vptr, Cint) $1 $emStI_H
Store: poStI_I(Vptr, Cint) $1 $emStI_I
Store: poStI_L(Vptr, Clong) $1 $emStI_L
Store: poStI_F(Vptr, Cfloat) $1 $emStI_F
Store: poStI_D(Vptr, Cdouble) $1 $emStI_D
Store: poStI_A(Vptr, Cptr) $1 $emStI_A
Store: poStE_B(Cptr, Vint) $1 $emStE_B
Store: poStE_H(Cptr, Vint) $1 $emStE_H
Store: poStE_I(Cptr, Vint) $1 $emStE_I
Store: poStE_L(Cptr, Vlong) $1 $emStE_L
Store: poStE_F(Cptr, Vfloat) $1 $emStE_F
Store: poStE_D(Cptr, Vdouble) $1 $emStE_D
Store: poStE_A(Cptr, Vptr) $1 $emStE_A
Store: poStEI_B(Cptr, Cint) $1 $emStEI_B
Store: poStEI_H(Cptr, Cint) $1 $emStEI_H
Store: poStEI_I(Cptr, Cint) $1 $emStEI_I
Store: poStEI_L(Cptr, Clong) $1 $emStEI_L
Store: poStEI_F(Cptr, Cfloat) $1 $emStEI_F
Store: poStEI_D(Cptr, Cdouble) $1 $emStEI_D
Store: poStEI_A(Cptr, Cptr) $1 $emStEI_A
Store: poStG_B(Cptr, Vint) $1 $emStG_B
Store: poStG_H(Cptr, Vint) $1 $emStG_H
Store: poStG_I(Cptr, Vint) $1 $emStG_I
Store: poStG_L(Cptr, Vlong) $1 $emStG_L
Store: poStG_F(Cptr, Vfloat) $1 $emStG_F
Store: poStG_D(Cptr, Vdouble) $1 $emStG_D
Store: poStG_A(Cptr, Vptr) $1 $emStG_A
Store: poStGI_B(Cptr, Cint) $1 $emStGI_B
Store: poStGI_H(Cptr, Cint) $1 $emStGI_H
Store: poStGI_I(Cptr, Cint) $1 $emStGI_I
Store: poStGI_L(Cptr, Clong) $1 $emStGI_L
Store: poStGI_F(Cptr, Cfloat) $1 $emStGI_F
Store: poStGI_D(Cptr, Cdouble) $1 $emStGI_D
Store: poStGI_A(Cptr, Cptr) $1 $emStGI_A
Store: poStV_B(Vptr, Vint) $1 $emStV_B
Store: poStV_H(Vptr, Vint) $1 $emStV_H
Store: poStV_I(Vptr, Vint) $1 $emStV_I
Store: poStV_L(Vptr, Vlong) $1 $emStV_L
Store: poStV_F(Vptr, Vfloat) $1 $emStV_F
Store: poStV_D(Vptr, Vdouble) $1 $emStV_D
Store: poStV_A(Vptr, Vptr) $1 $emStV_A
Store: poStVI_B(Vptr, Cint) $1 $emStVI_B
Store: poStVI_H(Vptr, Cint) $1 $emStVI_H
Store: poStVI_I(Vptr, Cint) $1 $emStVI_I
Store: poStVI_L(Vptr, Clong) $1 $emStVI_L
Store: poStVI_F(Vptr, Cfloat) $1 $emStVI_F
Store: poStVI_D(Vptr, Cdouble) $1 $emStVI_D
Store: poStVI_A(Vptr, Cptr) $1 $emStVI_A
Store: poStVE_B(Cptr, Vint) $1 $emStVE_B
Store: poStVE_H(Cptr, Vint) $1 $emStVE_H
Store: poStVE_I(Cptr, Vint) $1 $emStVE_I
Store: poStVE_L(Cptr, Vlong) $1 $emStVE_L
Store: poStVE_F(Cptr, Vfloat) $1 $emStVE_F
Store: poStVE_D(Cptr, Vdouble) $1 $emStVE_D
Store: poStVE_A(Cptr, Vptr) $1 $emStVE_A
Store: poStVEI_B(Cptr, Cint) $1 $emStVEI_B
Store: poStVEI_H(Cptr, Cint) $1 $emStVEI_H
Store: poStVEI_I(Cptr, Cint) $1 $emStVEI_I
Store: poStVEI_L(Cptr, Clong) $1 $emStVEI_L
Store: poStVEI_F(Cptr, Cfloat) $1 $emStVEI_F
Store: poStVEI_D(Cptr, Cdouble) $1 $emStVEI_D
Store: poStVEI_A(Cptr, Cptr) $1 $emStVEI_A
Store: poStVG_B(Cptr, Vint) $1 $emStVG_B
Store: poStVG_H(Cptr, Vint) $1 $emStVG_H
Store: poStVG_I(Cptr, Vint) $1 $emStVG_I
Store: poStVG_L(Cptr, Vlong) $1 $emStVG_L
Store: poStVG_F(Cptr, Vfloat) $1 $emStVG_F
Store: poStVG_D(Cptr, Vdouble) $1 $emStVG_D
Store: poStVG_A(Cptr, Vptr) $1 $emStVG_A
Store: poStVGI_B(Cptr, Cint) $1 $emStVGI_B
Store: poStVGI_H(Cptr, Cint) $1 $emStVGI_H
Store: poStVGI_I(Cptr, Cint) $1 $emStVGI_I
Store: poStVGI_L(Cptr, Clong) $1 $emStVGI_L
Store: poStVGI_F(Cptr, Cfloat) $1 $emStVGI_F
Store: poStVGI_D(Cptr, Cdouble) $1 $emStVGI_D
Store: poStVGI_A(Cptr, Cptr) $1 $emStVGI_A
Store: poSt_I(poAddI_A(Vptr, Cint), Vint) $0 $emSt_IRegisterIndirect
Store: poStI_I(poAddI_A(Vptr, Cint), Cint) $0 $emStI_IRegisterIndirect
// Store, Vint: poMEnter_A(Vptr) $1 $emMEnter_A
// Store, Vint: poMEnterG_A(Cptr) $1 $emMEnterG_A
// Store, Vint: poMExit_A(Vptr) $1 $emMExit_A
// Store, Vint: poMExitG_A(Cptr) $1 $emMExitG_A
// Vptr: poLookupV_A(Vptr, Cint) $1 $emLookupV_A
// Vptr: poLookupI_A(Vptr, Cint) $1 $emLookupI_A
// ...: poSysCall(M) $1 $emSysCall
// Store, ...: poSysCallV(M) $1 $emSysCallV
// ..., E: poSysCallE(M) $1 $emSysCallE
// Store, ..., E: poSysCallEV(M) $1 $emSysCallEV
//Store, ..., E: poCall(Va) $1 $emCall
VInt: poCallI $1 $emCallI_I
Vlong: poCallI $1 $emCallI_L
Vfloat: poCallI $1 $emCallI_F
Vdouble: poCallI $1 $emCallI_D
Vptr: poCallI $1 $emCallI_P
// Store, ..., E: poCallF(F) $1 $emCallF
%

Просмотреть файл

@ -0,0 +1,113 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ../../../..
CPPSRCS = x86-win32.nad.burg.cpp \
x86ArgumentList.cpp \
x86Opcode.cpp \
x86Win32Emitter.cpp \
x86Win32Instruction.cpp \
x86Formatter.cpp \
x86StdCall.cpp \
x86Float.cpp \
$(OS_SUPPORT) \
$(NULL)
LOCAL_MD_EXPORTS_x86 = x86ArgumentList.h \
x86Float.h \
x86Formatter.h \
x86Linux_Support.h \
x86Opcode.h \
x86StdCall.h \
x86Win32Cpu.h \
x86Win32Emitter.h \
x86Win32Instruction.h \
$(NULL)
MODULE_NAME = EF
#######################################################################
# (2) Include "component" configuration information. #
#######################################################################
include $(DEPTH)/config/config.mk
#######################################################################
# (3) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#
# Generation of OS-specific support files
#
ifeq ($(OS_ARCH),WINNT)
OS_SUPPORT = x86Win32_Support.cpp
endif
ifeq ($(OS_ARCH),Linux)
ASFILES = x86Linux.s
OS_SUPPORT = x86Linux_Support.cpp
endif
#######################################################################
# (4) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
#
# Rules to generate x86-win32.nad.burg.[cpp][h]
#
ifneq ($(OS_ARCH),WINNT)
x86-win32.nad.burg.cpp: x86-win32.nad.burg $(BURG)
$(BURG) -I -o $@ < $<
x86-win32.nad.burg: x86-win32.nad $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations $(DEPTH)/Tools/Nad/nad.pl
$(PERL) $(DEPTH)/Tools/Nad/nad.pl $< $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations \
$(LOCAL_EXPORT_DIR)/PrimitiveOperations.h \
$(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.cpp \
$<.burg.h > $@
else
x86-win32.nad.burg.cpp: x86-win32.nad $(BURG) $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations $(DEPTH)/Tools/Nad/nad.pl
$(DEPTH)/config/genburg.bat $(BURG) $(DEPTH)/Tools/Nad/nad.pl $< $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations
cp $(DEPTH)/Compiler/PrimitiveGraph/PrimitiveOperations.h $(LOCAL_EXPORT_DIR)
endif
#
# Extra cleaning
#
clean clobber realclean clobber_all::
rm -f x86-win32.nad.burg.cpp x86-win32.nad.burg.h x86-win32.nad.burg
#
# Special rules for x86Win32Support.cpp on Windows: it currently breaks the
# compiler if compiled with optimizations
#
ifeq ($(OS_ARCH),WINNT)
OPT_FLAG = -O2
$(OBJDIR)/x86Win32_Support$(OBJ_SUFFIX): x86Win32_Support.cpp
$(CCC) -c $(filter-out $(OPT_FLAG),$(CFLAGS)) $< -Fo$@
endif

Просмотреть файл

@ -0,0 +1,31 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
NAD_SRC = "{MOZ_SRC}:ns:electricalfire:Compiler:CodeGenerator:md:x86:x86-win32.nad"
PRIMITIVEOPERATIONS = "{MOZ_SRC}:ns:electricalfire:Compiler:PrimitiveGraph:PrimitiveOperations"
NAD = {PERL} "{MOZ_SRC}:ns:electricalfire:Tools:Nad:Nad.pl"
NAD_OUTPUTS = {NAD_SRC}.burg.h {NAD_SRC}.burg.cpp {PRIMITIVEOPERATIONS}.h {PRIMITIVEOPERATIONS}.cpp
{NAD_OUTPUTS} Ä {NAD_SRC} {PRIMITIVEOPERATIONS}
{NAD} {NAD_SRC} {PRIMITIVEOPERATIONS} {PRIMITIVEOPERATIONS}.h {PRIMITIVEOPERATIONS}.cpp {NAD_SRC}.burg.h > BurgOut
BURG -I <BurgOut > {NAD_SRC}.burg.cpp
set TouchedFiles "`ResolveAlias {PRIMITIVEOPERATIONS}.h`"
set TouchedFiles "{TouchedFiles},`ResolveAlias {NAD_SRC}.burg.h`"
set TouchedFiles "{TouchedFiles},`ResolveAlias {NAD_SRC}.burg.cpp`"
set TouchedFiles "{TouchedFiles},`ResolveAlias {PRIMITIVEOPERATIONS}.cpp`"
export TouchedFiles

Просмотреть файл

@ -0,0 +1,390 @@
%top
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Burg.h"
%
%terminals
%
%startsymbols
Control
Result
Exception
Store
Vcond
Vint
Vlong
Vfloat
Vdouble
Vptr
Cint
Clong
Cfloat
Cdouble
Cptr
Tuple
%
%grammar
Vint: coReg_I $1 $
Vlong: coReg_L $1 $
Vfloat: coReg_F $1 $
Vdouble: coReg_D $1 $
Vptr: coReg_A $1 $
Vcond: coReg_C $1 $
Store: coReg_M $1 $
Cint: coReg_I $1 $
Clong: coReg_L $1 $
Cfloat: coReg_F $1 $
Cdouble: coReg_D $1 $
Cptr: coReg_A $1 $
Vint: poConst_I $1 $emConst_I
Vlong: poConst_L $1 $emConst_L
Vptr: poConst_A $1 $emConst_A
Vfloat: poConst_F $1 $emConst_F
Vdouble: poConst_D $1 $emConst_D
// Vcond: poConst_C $1 $emConst_C
//-----------------------------------------------------------------
// Addressing Mode Helpers
Scale: poShl_I(Vint, poConst_I) $0
ScaleIndex: poAdd_A(Vptr, Scale) $0
//ScaleIndex: Vptr $0
DispScaleIndex: poAdd_A(ScaleIndex, poConst_I) $0
MemDSI: poLd_I(DispScaleIndex) $0
Disp: poAdd_A(Vptr, poConst_I) $0
MemDisp: poLd_I(Disp) $0
//-----------------------------------------------------------------
Store: poBreak(Store) $1 $emBreak
Vint: poArg_I $1 $
Vlong: poArg_L $1 $
Vfloat: poArg_F $1 $
Vdouble: poArg_D $1 $
Vptr: poArg_A $1 $
Store: poArg_M $1 $
Result: poResult_I(Vint) $1 $emResult_I
Result: poResult_A(Vptr) $1 $emResult_A
Result: poResult_L(Vlong) $1 $emResult_L
Result: poResult_F(Vfloat) $1 $emResult_F
Result: poResult_D(Vdouble) $1 $emResult_D
// Result: poResult_C(Acond) $1 $emResult_C
Result: poResult_M(Store) $1 $
//-----------------------------------------------------------------
// Conditional Branches
Control: poIfLt(Vcond) $1 $emIfLt
Control: poIfEq(Vcond) $1 $emIfEq
Control: poIfLe(Vcond) $1 $emIfLe
Control: poIfGt(Vcond) $1 $emIfGt
Control: poIfLgt(Vcond) $1 $emIfLgt
Control: poIfGe(Vcond) $1 $emIfGe
Control: poIfULt(Vcond) $1 $emIfULt
Control: poIfUEq(Vcond) $1 $emIfUEq
Control: poIfULe(Vcond) $1 $emIfULe
Control: poIfUGt(Vcond) $1 $emIfUGt
Control: poIfNe(Vcond) $1 $emIfNe
Control: poIfUGe(Vcond) $1 $emIfUGe
//-----------------------------------------------------------------
// Booleans
Vint: poLt_I(Vcond) $1 $emLt_I
Vint: poEq_I(Vcond) $1 $emEq_I
Vint: poLe_I(Vcond) $1 $emLe_I
Vint: poGt_I(Vcond) $1 $emGt_I
Vint: poLgt_I(Vcond) $1 $emLgt_I
Vint: poGe_I(Vcond) $1 $emGe_I
Vint: poULt_I(Vcond) $1 $emULt_I
Vint: poUEq_I(Vcond) $1 $emUEq_I
Vint: poULe_I(Vcond) $1 $emULe_I
Vint: poUGt_I(Vcond) $1 $emUGt_I
Vint: poNe_I(Vcond) $1 $emNe_I
Vint: poUGe_I(Vcond) $1 $emUGe_I
//-----------------------------------------------------------------
// switch
Control: poSwitch(Vint) $1 $emSwitch
//-----------------------------------------------------------------
// And
Vint: poAnd_I(Vint, Vint) $1 $emAnd_I
Vint: poAnd_I(Vint, poConst_I) $1 $emAndI_I
Vlong: poAnd_L(Vlong, Vlong) $1 $emAnd_L
//-----------------------------------------------------------------
// Or
Vint: poOr_I(Vint, Vint) $1 $emOr_I
Vint: poOr_I(Vint, poConst_I) $1 $emOrI_I
Vlong: poOr_L(Vlong, Vlong) $1 $emOr_L
//-----------------------------------------------------------------
// Xor
Vint: poXor_I(Vint, Vint) $1 $emXor_I
Vint: poXor_I(Vint, poConst_I) $1 $emXorI_I
Vlong: poXor_L(Vlong, Vlong) $1 $emXor_L
//-----------------------------------------------------------------
// Add
Vint: poAdd_I(Vint, Vint) $1 $emAdd_I
Vptr: poAdd_A(Vptr, Vint) $1 $emAdd_A
Vint: poAdd_I(Vint, poConst_I) $1 $emAddI_I
Vptr: poAdd_A(Vptr, poConst_I) $1 $emAddI_A
Vlong: poAdd_L(Vlong, Vlong) $1 $emAdd_L
//-----------------------------------------------------------------
// Sub
Vint: poSub_I(poConst_I, Vint) $1 $emSubR_I
Vint: poSub_I(Vint, Vint) $1 $emSub_I
Vptr: poSub_A(Vptr, Vint) $1 $emSub_A
Vlong: poSub_L(Vlong, Vlong) $1 $emSub_L
//-----------------------------------------------------------------
// Mul
Vint: poMul_I(Vint, Vint) $1 $emMul_I
Vlong: poMul_L(Vlong, Vlong) $1 $emMul_L
//-----------------------------------------------------------------
// Div
Vint: poDiv_I(Vint, Vint) $1 $emDiv_I
Vint: poDivE_I(Vint, Vint) $1 $emDivE_I
Vint: poDivU_I(Vint, Vint) $1 $emDivU_I
Vint: poDivUE_I(Vint, Vint) $1 $emDivUE_I
Vint: poDiv_I(Vint, MemDSI) $1 $emDiv_I_MemDSI
Vint: poDivE_I(Vint, MemDSI) $1 $emDivE_I_MemDSI
Vint: poDiv_I(Vint, MemDSI) $1 $emDivU_I_MemDSI
Vint: poDivE_I(Vint, MemDSI) $1 $emDivUE_I_MemDSI
Vlong: poDiv_L(Vlong, Vlong) $1 $emDiv_L
Vlong: poDivE_L(Vlong, Vlong) $1 $emDivE_L
//-----------------------------------------------------------------
// Mod
Vint: poMod_I(Vint, Vint) $1 $emMod_I
Vint: poModE_I(Vint, Vint) $1 $emModE_I
Vint: poModU_I(Vint, Vint) $1 $emModU_I
Vint: poModUE_I(Vint, Vint) $1 $emModUE_I
Vint: poMod_I(Vint, MemDSI) $1 $emMod_I_MemDSI
Vint: poModE_I(Vint, MemDSI) $1 $emModE_I_MemDSI
Vint: poMod_I(Vint, MemDSI) $1 $emModU_I_MemDSI
Vint: poModE_I(Vint, MemDSI) $1 $emModUE_I_MemDSI
Vlong: poMod_L(Vlong, Vlong) $1 $emMod_L
Vlong: poModE_L(Vlong, Vlong) $1 $emModE_L
//-----------------------------------------------------------------
// Shl
Vint: poShl_I(Vint, Vint) $1 $emShl_I
Vint: poShl_I(Vint, poConst_I) $1 $emShlI_I
Vlong: poShl_L(Vlong, Vint) $1 $emShl_L
//-----------------------------------------------------------------
// Shr
Vint: poShr_I(Vint, Vint) $1 $emShr_I
Vint: poShr_I(Vint, poConst_I) $1 $emShrI_I
Vlong: poShr_L(Vlong, Vint) $1 $emShr_L
//-----------------------------------------------------------------
// Shru
Vint: poShrU_I(Vint, Vint) $1 $emShrU_I
Vint: poShrU_I(Vint, poConst_I) $1 $emShrUI_I
Vlong: poShrU_L(Vlong, Vint) $1 $emShrU_L
//-----------------------------------------------------------------
// sign extend
Vint: poExt_I(Vint, poConst_I) $1 $emExt_I
Vlong: poExt_L(Vlong, poConst_I) $1 $emExt_L
//-----------------------------------------------------------------
// Floating Point
Vfloat: poFAdd_F(Vfloat, Vfloat) $1 $emFAdd_F
Vdouble: poFAdd_D(Vdouble, Vdouble) $1 $emFAdd_D
Vfloat: poFSub_F(Vfloat, Vfloat) $1 $emFSub_F
Vdouble: poFSub_D(Vdouble, Vdouble) $1 $emFSub_D
Vfloat: poFMul_F(Vfloat, Vfloat) $1 $emFMul_F
Vdouble: poFMul_D(Vdouble, Vdouble) $1 $emFMul_D
Vfloat: poFDiv_F(Vfloat, Vfloat) $1 $emFDiv_F
Vdouble: poFDiv_D(Vdouble, Vdouble) $1 $emFDiv_D
Vfloat: poFRem_F(Vfloat, Vfloat) $1 $emFRem_F
Vdouble: poFRem_D(Vdouble, Vdouble) $1 $emFRem_D
//-----------------------------------------------------------------
// Convert
Vint: poConvI_L(Vlong) $1 $emConvI_L
Vlong: poConvL_I(Vint) $1 $emConvL_I
Vint: poFConvI_F(Vfloat) $1 $emFConvI_F
Vint: poFConvI_D(Vdouble) $1 $emFConvI_D
Vlong: poFConvL_F(Vfloat) $1 $emFConvL_F
Vlong: poFConvL_D(Vdouble) $1 $emFConvL_D
Vfloat: poFConvF_I(Vint) $1 $emFConvF_I
Vfloat: poFConvF_L(Vlong) $1 $emFConvF_L
Vfloat: poFConvF_D(Vdouble) $1 $emFConvF_D
Vdouble: poFConvD_I(Vint) $1 $emFConvD_I
Vdouble: poFConvD_L(Vlong) $1 $emFConvD_L
Vdouble: poFConvD_F(Vfloat) $1 $emFConvD_F
//-----------------------------------------------------------------
// Compare
Vcond: poCmp_I(Vint, Vint) $1 $emCmp_I
Vcond: poCmpU_I(Vint, Vint) $1 $emCmpU_I
Vcond: poCmpU_A(Vptr, Vptr) $1 $emCmpU_A
Vcond: poCmp_I(Vint, poConst_I) $1 $emCmpI_I
Vcond: poCmpU_I(Vint, poConst_I) $1 $emCmpUI_I
Vint: poCatL_I(poCmp_L(Vlong, Vlong)) $1 $em3wayCmpL_L
Vint: poCatCL_I(poCmp_L(Vlong, Vlong)) $1 $em3wayCmpCL_L
Vint: poCatL_I(poFCmp_F(Vfloat, Vfloat)) $1 $em3wayCmpF_L
Vint: poCatG_I(poFCmp_F(Vfloat, Vfloat)) $1 $em3wayCmpF_G
Vint: poCatL_I(poFCmp_D(Vdouble, Vdouble)) $1 $em3wayCmpD_L
Vint: poCatG_I(poFCmp_D(Vdouble, Vdouble)) $1 $em3wayCmpD_G
Vint: poCatCL_I(poFCmp_F(Vfloat, Vfloat)) $1 $em3wayCmpCF_L
Vint: poCatCG_I(poFCmp_F(Vfloat, Vfloat)) $1 $em3wayCmpCF_G
Vint: poCatCL_I(poFCmp_D(Vdouble, Vdouble)) $1 $em3wayCmpCD_L
Vint: poCatCG_I(poFCmp_D(Vdouble, Vdouble)) $1 $em3wayCmpCD_G
Vcond: poCmp_I(MemDSI, poConst_I) $1 $emCmpI_I_MemDSI
Vcond: poCmp_I(MemDSI, Vint) $1 $emCmp_I_MemDSI
//-----------------------------------------------------------------
// CheckNull
Exception: poChkNull(Vptr) $1 $emChkNull
//-----------------------------------------------------------------
// Limit
Exception: poLimit(Vint, Vint) $1 $emLimit
Exception: poLimit(poConst_I, Vint) $1 $emLimitR
Exception: poLimit(poConst_I, MemDisp) $1 $emLimitR_MemDisp
Exception: poLimit(Vint, MemDisp) $1 $emLimit_MemDisp
//-----------------------------------------------------------------
// Check/Limit Cast
Exception: poChkCast_A(Vptr, poConst_A) $1 $emChkCastI_A
Exception: poChkCast_A(Vptr, Vptr) $1 $emChkCast_A
Exception: poChkCast_I(Vint, Vint) $1 $emChkCast_I
Exception: poLimCast(Vint) $1 $emLimCast
//-----------------------------------------------------------------
// Load
Vint: poLd_I(Vptr) $1 $emLd_I
Vptr: poLd_A(Vptr) $1 $emLd_A
Vlong: poLd_L(Vptr) $1 $emLd_L
Vfloat: poLd_F(Vptr) $1 $emLd_F
Vdouble: poLd_D(Vptr) $1 $emLd_D
Vint: poLdS_B(Vptr) $1 $emLdS_B
Vint: poLdU_B(Vptr) $1 $emLdU_B
Vint: poLdS_H(Vptr) $1 $emLdS_H
Vint: poLdU_H(Vptr) $1 $emLdU_H
Vint: MemDisp $1 $emLd_I_MemDisp
Vint: MemDSI $1 $emLd_I_MemDSI
// FIXME - Add these patterns for performance
// Vfloat: poLd_F(Disp) $1 $emLd_F_MemDisp
// Vfloat: poLd_F(DispScaleIndex) $1 $emLd_F_MemDSI
// Vdouble: poLd_D(Disp) $1 $emLd_D_MemDisp
// Vdouble: poLd_D(DispScaleIndex) $1 $emLd_D_MemDSI
//-----------------------------------------------------------------
// Store
Store: poSt_I(Vptr, Vint) $1 $emSt_I
Store: poSt_I(Vptr, poConst_I) $1 $emStI_I
Store: poSt_A(Vptr, Vptr) $1 $emSt_A
Store: poSt_L(Vptr, Vlong) $1 $emSt_L
Store: poSt_B(Vptr, Vint) $1 $emSt_B
Store: poSt_H(Vptr, Vint) $1 $emSt_H
Store: poSt_I(Disp, poConst_I) $1 $emStI_I_MemDisp
Store: poSt_I(Disp, Vint) $1 $emSt_I_MemDisp
Store: poSt_I(DispScaleIndex, Vint) $1 $emSt_I_MemDSI
Store: poSt_F(Vptr, Vfloat) $1 $emSt_F
Store: poSt_D(Vptr, Vdouble) $1 $emSt_D
// FIXME - Add below patterns for performance
//Store: poSt_F(Disp, poConst_I) $1 $emStI_F_MemDisp
//Store: poSt_F(Disp, Vint) $1 $emSt_F_MemDisp
//Store: poSt_F(DispScaleIndex, Vint) $1 $emSt_F_MemDSI
//Store: poSt_D(Disp, poConst_I) $1 $emStI_D_MemDisp
//Store: poSt_D(Disp, Vint) $1 $emSt_D_MemDisp
//Store: poSt_D(DispScaleIndex, Vint) $1 $emSt_D_MemDSI
//-----------------------------------------------------------------
// Monitor
//Store: poMEnter_A(Vptr) $1 $emMEnter_A
//Store: poMExit_A(Vptr) $1 $emMExit_A
//-----------------------------------------------------------------
// Monitor
Store: poMEnter(Store, Vptr) $1 $emMEnter
Store: poMExit(Store, Vptr) $1 $emMExit
//-----------------------------------------------------------------
// Projections
Store: poProj_M $1 $
Vint: poProj_I $1 $
Vptr: poProj_A $1 $
Vlong: poProj_L $1 $
Vfloat: poProj_F $1 $
Vdouble: poProj_D $1 $
//-----------------------------------------------------------------
// Syscalls
Tuple: poSysCall $1 $emSysCall
Tuple: poSysCallE $1 $emSysCallE
Tuple: poSysCallC $1 $emSysCallC
Tuple: poSysCallEC $1 $emSysCallEC
Tuple: poSysCallV $1 $emSysCallV
Tuple: poSysCallEV $1 $emSysCallEV
//-----------------------------------------------------------------
// Calls
Tuple: poCall(Vptr) $1 $emDynamicCall
Tuple: poCall(poConst_A) $1 $emStaticCall
//-----------------------------------------------------------------
// Catch
Vptr: poCatch $1 $emCatch
%

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,519 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: x86ArgumentList.h
//
// Authors: Peter DeSantis
// Simon Holmes a Court
//
#ifndef _X86ARGUMENTLIST
#define _X86ARGUMENTLIST
/*
***********************************************************************************************************************************
x86 ArgumentLists
Anywhere from 0 to 10 bytes of information following the x86 Opcode.
Includes the ModR/M byte, the SIB byte, the Displacement field and the immediate field.
***********************************************************************************************************************************
*/
#include "CatchAssert.h"
#include <stdio.h>
#include "prtypes.h"
#include "ControlNodes.h"
#include "x86Opcode.h"
#include "MemoryAccess.h"
class x86ArgListInstruction;
enum x86ImmediateSize
{
isNoImmediate,
is1ByteImmediate,
is4ByteImmediate
};
enum x86ArgumentType
{
atRegDirect,
atRegAllocStackSlot, // Stack slot designated by the register allocator
atRegAllocStackSlotHi32, // Upper 32-bits of 64-bit stack slot designated by the register allocator
atRegisterIndirect, //
atRegisterRelative1ByteDisplacement,
atRegisterRelative4ByteDisplacement,
atBaseIndexed, //
atBaseRelativeIndexed1ByteDisplacement,
atBaseRelativeIndexed4ByteDisplacement,
atScaledIndexedBy2, //
atScaledIndexed1ByteDisplacementBy2,
atScaledIndexed4ByteDisplacementBy2,
atScaledIndexedBy4, //
atScaledIndexed1ByteDisplacementBy4,
atScaledIndexed4ByteDisplacementBy4,
atScaledIndexedBy8, //
atScaledIndexed1ByteDisplacementBy8,
atScaledIndexed4ByteDisplacementBy8,
atStackOffset,
atStackOffset1ByteDisplacement,
atStackOffset4ByteDisplacement,
atAbsoluteAddress,
atImmediateOnly
};
// Maps register alloc color to x86 machine register
extern x86GPR colorTox86GPR[];
// Maps x86 machine register to register alloc color
extern Uint8 x86GPRToColor[];
//--------------------------------------------------------------------------------
// x86ArgumentList
// Abstract base class
class x86ArgumentList
{
protected:
x86ArgumentList() { }
public:
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/) = 0;
virtual Uint8 alSize(x86ArgListInstruction& /*inInsn*/, MdFormatter& /*inFormatter*/) = 0;
virtual Uint8 alGetRegisterOperand( x86ArgListInstruction& /*inInsn*/ ) { return NOT_A_REG; }
virtual bool alSwitchArgumentTypeToSpill(Uint8 /*inWhichUse*/, x86ArgListInstruction& /* inInsn */ ) { return false;}
virtual x86ImmediateSize alSizeOfImmediate() { return isNoImmediate; }
virtual bool alIsRegisterDirect() { return true; }
#ifdef DEBUG
virtual void alCheckIntegrity(x86ArgListInstruction& /*inInsn*/) { /* do nothing for now, except for double argument list */ }
virtual void alPrintArgs(x86ArgListInstruction& /*inInsn*/) { /* do nothing for now, except for double argument list */ }
#endif // DEBUG
#ifdef DEBUG_LOG
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn) = 0;
#endif // DEBUG_LOG
};
//--------------------------------------------------------------------------------
// x86EmptyArgumentList
// Contains no information
class x86EmptyArgumentList :
public x86ArgumentList
{
public:
x86EmptyArgumentList() {}
virtual void alFormatToMemory(void* /*inStart*/, Uint32 /*inOffset*/, x86ArgListInstruction& /*inInsn*/, MdFormatter& /*inFormatter*/) {}
virtual Uint8 alSize(x86ArgListInstruction& /*inInsn*/, MdFormatter& /*inFormatter*/) { return 0; }
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject /*f*/, x86ArgListInstruction& /*inInsn*/) {}
#endif // DEBUG_LOG
};
//--------------------------------------------------------------------------------
// x86ControlNodeOffsetArgumentList
class x86ControlNodeOffsetArgumentList :
public x86ArgumentList
{
public:
x86ControlNodeOffsetArgumentList( ControlNode& inTarget ) : cnoTarget(inTarget) { }
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
// FIX In the future we would like short jumps to be encode with 1 byte immediates.
virtual Uint8 alSize(x86ArgListInstruction& /*inInsn*/, MdFormatter& /*inFormatter*/) { return 4; }
virtual x86ImmediateSize alSizeOfImmediate() { return is4ByteImmediate; }
protected:
ControlNode& cnoTarget;
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& /*inInsn*/);
#endif
};
/*================================================================================
The following argument lists all depend on the InstructionUses and InstructionDefines to contain the Virtual Registers
which have been assigned machine registers prior to printing or formating. Additionally, all make assumptions about the
properties of the uses and defines which hold the VRs.
Let the array of uses be enumerated u0, u1, u2,...un, and the array of defines d0, d1, d2,...dm.
These assumptions require the following:
For some ux, all ui i <= x are uses which contain VRs (represent machine registers) and all uj j > x are uses which do
not contain VRs (represent machine registers).
Similarly, For some dx, all ui i <= x are defines which contain VRs (represent machine registers) and all dj j > x are defines which do
not contain VRs (represent machine registers).
If some register/memory operand is overwritten then it encoded in the first use(s) and the first define(s).
Many of the functions use a wrap around approach. They take some offset into the uses array and expect to find the virtual registers
necessary to format themselves at that spot. If instead they find that they are beyond the end of the array of uses or that the current
use is not a VR, then they know that they can find they VRs at the beginning of the defines.
*/
//--------------------------------------------------------------------------------
// x86SingleArgumentList
// One register or memory operand
class x86SingleArgumentList :
public x86ArgumentList
{
public:
x86SingleArgumentList(x86ArgumentType inType);
x86SingleArgumentList(x86ArgumentType inType, Uint32 inDisplacement);
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alSize(x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual bool alSwitchArgumentTypeToSpill(Uint8 inWhichUse, x86ArgListInstruction& /* inInsn */);
virtual Uint8 alGetRegisterOperand( x86ArgListInstruction& inInsn );
virtual bool alIsRegisterDirect() { return argType1 == atRegDirect; }
protected:
x86SingleArgumentList() { }
// Utility functions used by all super classes of x86SingleArgumentList */
void alFormatToMemory(void* inStart, x86ArgListInstruction& inInsn, x86ArgumentType inType, Uint8 inInstructionUseStartIndex, MdFormatter& /*inFormatter*/);
Uint8 alSize(x86ArgumentType inType, x86ArgListInstruction& inInsn, Uint8 inInstructionUseStartIndex, MdFormatter& /*inFormatter*/);
x86ArgumentType argType1;
union
{
Uint8 arg1ByteDisplacement;
Uint32 arg4ByteDisplacement;
};
private:
void alFormatStackSlotToMemory(void* inStart, x86ArgListInstruction& inInsn, Uint8 inInstructionUseStartIndex, MdFormatter& /*inFormatter*/, int offset);
void alFormatNonRegToMemory(void* inStart, x86ArgListInstruction& inInsn, x86ArgumentType inType, MdFormatter& /*inFormatter*/);
void alFormatRegToMemory(void* inStart, x86ArgListInstruction& inInsn, x86ArgumentType inType, Uint8 inInstructionUseStartIndex, MdFormatter& /*inFormatter*/);
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn) { alPrintPretty(f, inInsn, argType1, 0); }
void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn, x86ArgumentType inType, Uint8 inInstructionUseStartIndex);
#endif // DEBUG_LOG
};
//--------------------------------------------------------------------------------
// x86DoubleArgumentList
// A memory and a register operand or two register operands
class x86DoubleArgumentList :
public x86SingleArgumentList
{
protected:
x86ArgumentType argType2;
public:
x86DoubleArgumentList(x86ArgumentType inType1, x86ArgumentType inType2);
x86DoubleArgumentList(x86ArgumentType inType1, x86ArgumentType inType2, Uint32 inDisplacement);
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alSize(x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alGetRegisterOperand( x86ArgListInstruction& /*inInsn*/ ) { return NOT_A_REG; }
virtual bool alSwitchArgumentTypeToSpill(Uint8 inWhichUse, x86ArgListInstruction& /* inInsn */ );
VirtualRegister* alGetArg1VirtualRegister(x86ArgListInstruction& inInsn);
VirtualRegister* alGetArg2VirtualRegister(x86ArgListInstruction& inInsn);
virtual bool alIsRegisterDirect() { return argType1 == atRegDirect && argType2 == atRegDirect; }
bool akIsArg1Direct() { return argType1 == atRegDirect; }
bool akIsArg2Direct() { return argType2 == atRegDirect; }
bool alHasTwoArgs(x86ArgListInstruction& inInsn);
#ifdef DEBUG
virtual void alCheckIntegrity(x86ArgListInstruction& inInsn);
virtual void alPrintArgs(x86ArgListInstruction& inInsn);
#endif // DEBUG
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn);
#endif // DEBUG_LOG
};
inline Uint8 x86DoubleArgumentList::
alSize(x86ArgListInstruction& inInsn, MdFormatter& inFormatter)
{
// The formatting of the mem argument determines the size of the argumentlist because one register direct can
// just be ORed.
int size;
if(argType1 != atRegDirect)
size = x86SingleArgumentList::alSize(argType1, inInsn, 0, inFormatter);
else
size = x86SingleArgumentList::alSize(argType2, inInsn, 1, inFormatter);
return size;
}
//--------------------------------------------------------------------------------
// x86ImmediateArgumentList
// One reg or mem operand and an immediate operand.
class x86ImmediateArgumentList :
public x86SingleArgumentList
{
public:
x86ImmediateArgumentList(x86ArgumentType inType1, Uint32 inImm);
x86ImmediateArgumentList(x86ArgumentType inType1, Uint32 inDisplacement, Uint32 inImm);
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alSize(x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual x86ImmediateSize alSizeOfImmediate() { return iSize; }
protected:
union
{
Uint8 imm1Byte;
Uint32 imm4Bytes;
};
x86ImmediateSize iSize;
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn);
#endif // DEBUG_LOG
};
inline x86ImmediateArgumentList::
x86ImmediateArgumentList(x86ArgumentType inType1, Uint32 inImm)
: x86SingleArgumentList(inType1)
{
imm4Bytes = inImm;
if(valueIsOneByteSigned(inImm))
iSize = is1ByteImmediate;
else
iSize = is4ByteImmediate;
}
inline x86ImmediateArgumentList::
x86ImmediateArgumentList(x86ArgumentType inType1, Uint32 inDisplacement, Uint32 inImm)
: x86SingleArgumentList(inType1, inDisplacement)
{
imm4Bytes = inImm;
if(valueIsOneByteSigned(inImm))
iSize = is1ByteImmediate;
else
iSize = is4ByteImmediate;
}
#ifdef DEBUG_LOG
inline void x86ImmediateArgumentList::
alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn)
{
x86SingleArgumentList::alPrintPretty(f, inInsn, argType1, 0 );
if (argType1 != atImmediateOnly)
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", "));
if(iSize == is1ByteImmediate)
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%0x", imm1Byte));
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%0x", imm4Bytes));
}
#endif // DEBUG_LOG
//--------------------------------------------------------------------------------
// x86CondensableImmediateArgumentList
class x86CondensableImmediateArgumentList :
public x86SingleArgumentList
{
public:
x86CondensableImmediateArgumentList(x86ArgumentType inType1, Uint32 inImm);
x86CondensableImmediateArgumentList(x86ArgumentType inType1, Uint32 inDisplacement, Uint32 inImm);
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alSize(x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual x86ImmediateSize alSizeOfImmediate() { return iSize; }
protected:
Uint32 imm4Bytes;
x86ImmediateSize iSize;
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn);
#endif // DEBUG_LOG
};
inline x86CondensableImmediateArgumentList::
x86CondensableImmediateArgumentList(x86ArgumentType inType1, Uint32 inImm)
: x86SingleArgumentList(inType1), imm4Bytes(inImm)
{
}
inline x86CondensableImmediateArgumentList::
x86CondensableImmediateArgumentList(x86ArgumentType inType1, Uint32 inDisplacement, Uint32 inImm)
: x86SingleArgumentList(inType1, inDisplacement), imm4Bytes(inImm)
{
}
#ifdef DEBUG_LOG
inline void x86CondensableImmediateArgumentList::
alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn)
{
x86SingleArgumentList::alPrintPretty(f, inInsn, argType1, 0 );
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", %0x", imm4Bytes));
}
#endif // DEBUG_LOG
//--------------------------------------------------------------------------------
// x86DoubleImmediateArgumentList
// [ immediate argument, mem, and reg] or [immediate argument, two reg operands]
class x86DoubleImmediateArgumentList :
public x86DoubleArgumentList
{
public:
x86DoubleImmediateArgumentList(x86ArgumentType inType1, x86ArgumentType inType2, Uint32 inImm);
x86DoubleImmediateArgumentList(x86ArgumentType inType1, x86ArgumentType inType2, Uint32 inDisplacement, Uint32 inImm);
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alSize(x86ArgListInstruction& /*inInsn*/, MdFormatter& /*inFormatter*/);
virtual x86ImmediateSize alSizeOfImmediate() { return iSize; }
protected:
union
{
Uint8 imm1Byte;
Uint32 imm4Bytes;
};
x86ImmediateSize iSize;
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn);
#endif // DEBUG_LOG
};
inline x86DoubleImmediateArgumentList::
x86DoubleImmediateArgumentList(x86ArgumentType inType1, x86ArgumentType inType2, Uint32 inImm)
: x86DoubleArgumentList(inType1, inType2)
{
imm4Bytes = inImm;
// if(valueIsOneByteSigned(inImm))
// iSize = is1ByteImmediate;
// else
iSize = is4ByteImmediate;
}
inline x86DoubleImmediateArgumentList::
x86DoubleImmediateArgumentList(x86ArgumentType inType1, x86ArgumentType inType2, Uint32 inDisplacement, Uint32 inImm)
: x86DoubleArgumentList(inType1, inType2, inDisplacement)
{
imm4Bytes = inImm;
// if(valueIsOneByteSigned(inImm)) // FIX
// iSize = is1ByteImmediate;
// else
iSize = is4ByteImmediate;
}
inline Uint8 x86DoubleImmediateArgumentList::
alSize(x86ArgListInstruction& inInsn, MdFormatter& inFormatter)
{
Uint32 size = x86DoubleArgumentList::alSize(inInsn, inFormatter);
if(iSize == is1ByteImmediate)
size += 1;
else
size += 4;
return size;
}
inline void x86DoubleImmediateArgumentList::
alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& inFormatter)
{
x86DoubleArgumentList::alFormatToMemory(inStart, inOffset, inInsn, inFormatter);
Uint8* immLocation = (Uint8*)inStart + x86DoubleArgumentList::alSize(inInsn, inFormatter);
if(iSize == is1ByteImmediate)
*immLocation = imm1Byte;
else
writeLittleWordUnaligned((void*)immLocation, imm4Bytes);
}
#ifdef DEBUG_LOG
inline void x86DoubleImmediateArgumentList::
alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn)
{
x86DoubleArgumentList::alPrintPretty(f, inInsn);
if(iSize == is1ByteImmediate)
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", %0x", imm1Byte));
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (", %0x", imm4Bytes));
}
#endif // DEBUG_LOG
//--------------------------------------------------------------------------------
// x86SpecialRegMemArgumentList
// Only used with x86SpecialRegMemOpcode
// This argument list holds an immediate value and a single argument. In its initial form it emits a double argument list
// of the one register operand. If it is switched to spill type it prints the memory operand and the immediate value.
class x86SpecialRegMemArgumentList :
public x86ImmediateArgumentList
{
public:
x86SpecialRegMemArgumentList(Uint32 inImm) : x86ImmediateArgumentList(atRegDirect, inImm) { }
virtual void alFormatToMemory(void* inStart, Uint32 inOffset, x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
virtual Uint8 alSize(x86ArgListInstruction& inInsn, MdFormatter& /*inFormatter*/);
#ifdef DEBUG_LOG
public:
virtual void alPrintPretty(LogModuleObject &f, x86ArgListInstruction& inInsn);
#endif // DEBUG_LOG
};
inline Uint8 x86SpecialRegMemArgumentList::
alSize(x86ArgListInstruction& inInsn, MdFormatter& inFormatter)
{
Uint8 size;
if(argType1 == atRegDirect)
size = 1; // Only need the ModR/M byte
else
size = x86ImmediateArgumentList::alSize(inInsn, inFormatter);
return size;
}
#endif //X86_ARGUMENTLIST

Просмотреть файл

@ -0,0 +1,732 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86Float.cpp - Floating-point code-generation for x86 processors
//
#include "x86Float.h"
#include "x86Win32Emitter.h"
#include "FloatUtils.h"
// Note: In comments below, TOS = Top of FPU stack
//====================================================================================================
// Register classes for float and double operands
// FIXME - For now, all float and double virtual registers are allocated on the stack
const VRClass vrcFloat = vrcStackSlot;
const VRClass vrcDouble = vrcStackSlot; // FIXME - Stack slots are temporarily 8-bytes, so they can hold a double
//====================================================================================================
// Floating-point instruction classes
/*--------------------------------------------------------------------------------
Floating-Point instructions where one operand is a memory location and the other is
the top of stack, e.g. binary operations like add, and load/store/conversion instructions.
oiBaseOpcode
contains the opcode for the instruction
oiOpcodeInformation
6 set if opcode extension is used
[5 4 3] contain Regfield opcode extension (if bit 6 is set)
others set to 0
*/
// Utility macros for setting up opcode table
#define NO_EXTENSION 8 // Register extensions range from 0 to 7, so this special code indicates that
// there is no R/M byte
#define FLOAT_INFO(first_opcode, reg_extension) \
first_opcode, ((reg_extension != NO_EXTENSION) * ((1<< 6) | ((reg_extension) << 3)))
x86OpcodeInfo InsnFloatMemory::opcodeTable[] =
{
{FLOAT_INFO(0xD9, 3), "fstp32"}, // TOS => 32-bit float memory. Pop TOS.
{FLOAT_INFO(0xDD, 3), "fstp64"}, // TOS => 64-bit double memory. Pop TOS.
{FLOAT_INFO(0xD9, 2), "fst32"}, // TOS => 32-bit float memory. (Don't pop FPU stack.)
{FLOAT_INFO(0xDD, 2), "fst64"}, // TOS => 64-bit double memory. (Don't pop FPU stack.)
{FLOAT_INFO(0xDB, 3), "fistp32"}, // Round(TOS) => 32-bit int memory. Pop TOS.
{FLOAT_INFO(0xDF, 7), "fistp64"}, // Round(TOS) => 64-bit long memory. Pop TOS.
{FLOAT_INFO(0xD9, 0), "fld32"}, // 32-bit float memory => Push on FPU stack
{FLOAT_INFO(0xDD, 0), "fld64"}, // 64-bit float memory => Push on FPU stack
{FLOAT_INFO(0xDB, 0), "fild32"}, // 32-bit int memory => convert to FP and push on FPU stack
{FLOAT_INFO(0xDF, 5), "fild64"}, // 64-bit long memory => convert to FP and push on FPU stack
{FLOAT_INFO(0xD8, 0), "fadd32"}, // Add TOS and 32-bit float memory => replace TOS
{FLOAT_INFO(0xDC, 0), "fadd64"}, // Add TOS and 64-bit double memory => replace TOS
{FLOAT_INFO(0xD8, 1), "fmul32"}, // Multiply TOS and 32-bit float memory => replace TOS
{FLOAT_INFO(0xDC, 1), "fmul64"}, // Multiply TOS and 64-bit double memory => replace TOS
{FLOAT_INFO(0xD8, 4), "fsub32"}, // Subtract TOS from 32-bit float memory => replace TOS
{FLOAT_INFO(0xDC, 4), "fsub64"}, // Subtract TOS from 64-bit double memory => replace TOS
{FLOAT_INFO(0xD8, 5), "fsubr32"}, // Subtract 32-bit float memory from TOS => replace TOS
{FLOAT_INFO(0xDC, 5), "fsubr64"}, // Subtract 64-bit double memory from TOS => replace TOS
{FLOAT_INFO(0xD8, 6), "fdiv32"}, // Divide TOS by 32-bit float memory => replace TOS
{FLOAT_INFO(0xDC, 6), "fdiv64"}, // Divide TOS by 64-bit double memory => replace TOS
{FLOAT_INFO(0xD8, 3), "fcomp32"}, // Compare TOS to 32-bit float memory, setting FPU flags, pop TOS
{FLOAT_INFO(0xDC, 3), "fcomp64"} // Compare TOS to 64-bit double memory, setting FPU flags, pop TOS
};
void InsnFloatMemory::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter)
{
assert(opcodeInfo != NULL && iArgumentList != NULL);
Uint8 *opLocation = (Uint8*)inStart;
// Format the opcode to memory
*opLocation++ = opcodeInfo->oiBaseOpcode;
// Find the location of the argument list and format it to memory
iArgumentList->alFormatToMemory((void*)opLocation, inOffset, *this, inFormatter);
// If the opcode has an opcode extension then OR it into the proper place. ( the reg field of the modr/m byte.)
Uint8 regFieldExtension = kRegfield_Mask & opcodeInfo->oiOpcodeInformation;
*opLocation |= regFieldExtension;
}
/*----------------------------------------------------------------------------------------------------------
Floating-Point instructions where source and destination are implicitly on the FPU stack
e.g. negation, comparison
oiBaseOpcode
contains the first byte of the opcode for the instruction
oiOpcodeInformation
contains the second byte of the opcode for the instruction
*/
x86OpcodeInfo InsnFloatReg::opcodeTable[] =
{
{0xDF, 0xE9, "fucomip st, st(1)"}, // Compare top two operands on FPU stack and set EFLAGS, pop FPU stack
{0xD9, 0xE0, "fchs"}, // Negate top of stack value
{0xDF, 0xE0, "fnstsw ax"} // Copy FPU status register to AX
};
void InsnFloatReg::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
// Format the opcode to memory. There is no argument list.
Uint8* start = (Uint8*) inStart;
*start++ = opcodeInfo->oiBaseOpcode;
*start = opcodeInfo->oiOpcodeInformation;
}
//====================================================================================================
// Instruction generation utilities
InsnDoubleOpDir& x86Win32Emitter::
copyFromFloatToIntegerRegister(DataNode& inDataNode, InsnUseXDefineYFromPool& defInsn)
{
VirtualRegister& vr = defineTemporary(defInsn, 0, vrcStackSlot);
InsnDoubleOpDir& copyInsn = *new(mPool) InsnDoubleOpDir(&inDataNode, mPool, raCopyI, atRegAllocStackSlot, atRegDirect, 1, 1);
useTemporaryVR(copyInsn, vr, 0);
return copyInsn;
}
InsnDoubleOpDir& x86Win32Emitter::
copyFromIntegerRegisterToFloat(DataNode& inDataNode, InsnUseXDefineYFromPool& defInsn)
{
VirtualRegister& vr = defineTemporary(defInsn, 0);
InsnDoubleOpDir& copyInsn = *new(mPool) InsnDoubleOpDir(&inDataNode, mPool, raCopyI, atRegDirect, atRegAllocStackSlot, 1, 1);
useTemporaryVR(copyInsn, vr, 0);
return copyInsn;
}
//====================================================================================================
// Floating-point binary operations, i.e. add, subtract, multiply, divide, modulus
void x86Win32Emitter::
emit_BinaryFloat(Primitive& inPrimitive,
x86FloatMemoryType binary_op, x86FloatMemoryType load_op, x86FloatMemoryType store_op,
VRClass vrClass)
{
// Fetch first operand of binary op from memory and push it on the FPU stack
InsnFloatMemory &loadInsn = *new InsnFloatMemory(&inPrimitive, mPool, load_op, 1, 1);
useProducer(inPrimitive.nthInputVariable(0), loadInsn, 0, vrClass);
InstructionDefine& define1 = defineTemporaryOrder(loadInsn, 0);
// Fetch second operand and perform binary operation, result replaces top of FPU stack
InsnFloatMemory &binaryInsn = *new InsnFloatMemory(&inPrimitive, mPool, binary_op, 2, 1);
useProducer(inPrimitive.nthInputVariable(1), binaryInsn, 0, vrClass);
useTemporaryOrder(binaryInsn, define1, 1);
InstructionDefine& define2 = defineTemporaryOrder(binaryInsn, 0);
// Pop result of binary operation from FPU stack and store into memory
InsnFloatMemory &storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, store_op, 1, 1);
useTemporaryOrder(storeInsn, define2, 0);
defineProducer(inPrimitive, storeInsn, 0, vrClass); // result
}
// Emit 32-bit float binary operation
void x86Win32Emitter::
emit_BinaryFloat32(Primitive& inPrimitive, x86FloatMemoryType binary_op)
{
emit_BinaryFloat(inPrimitive, binary_op, fld32, fstp32, vrcFloat);
}
// Emit 64-bit float binary operation
void x86Win32Emitter::
emit_BinaryFloat64(Primitive& inPrimitive, x86FloatMemoryType binary_op)
{
emit_BinaryFloat(inPrimitive, binary_op, fld64, fstp64, vrcDouble);
}
void x86Win32Emitter::
emit_FAdd_F(Primitive& inPrimitive) {
emit_BinaryFloat32(inPrimitive, fadd32);
}
void x86Win32Emitter::
emit_FAdd_D(Primitive& inPrimitive) {
emit_BinaryFloat64(inPrimitive, fadd64);
}
void x86Win32Emitter::
emit_FMul_F(Primitive& inPrimitive) {
emit_BinaryFloat32(inPrimitive, fmul32);
}
void x86Win32Emitter::
emit_FMul_D(Primitive& inPrimitive) {
emit_BinaryFloat64(inPrimitive, fmul64);
}
void x86Win32Emitter::
emit_FSub_F(Primitive& inPrimitive) {
emit_BinaryFloat32(inPrimitive, fsub32);
}
void x86Win32Emitter::
emit_FSub_D(Primitive& inPrimitive) {
emit_BinaryFloat64(inPrimitive, fsub64);
}
void x86Win32Emitter::
emit_FDiv_F(Primitive& inPrimitive) {
emit_BinaryFloat32(inPrimitive, fdiv32);
}
void x86Win32Emitter::
emit_FDiv_D(Primitive& inPrimitive) {
emit_BinaryFloat64(inPrimitive, fdiv64);
}
// FIXME - Modulus is wrapper around fmod function. Should be changed to inline code.
void x86Win32Emitter::
emit_FRem_D(Primitive& inPrimitive)
{
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)(void))&javaFMod);
}
// Wrapper around fmod() for 32-bit float operands instead of double operands
static Flt32 fmod32(Flt32 a, Flt32 b)
{
return (Flt32)javaFMod(a, b);
}
void x86Win32Emitter::
emit_FRem_F(Primitive& inPrimitive)
{
new(mPool) CallS_C(&inPrimitive, mPool, 2, true, *this, (void (*)(void))&fmod32);
}
//-----------------------------------------------------------------------------------------------------------
// Conversions to/from floating-point
//
// All conversions are two steps:
// 1) Load input operand onto FPU stack from memory, with possible conversion to floating-point type
// 2) Simultaneously convert and store from top of FPU stack into memory location, with possible
// conversion to integer type.
void x86Win32Emitter::
emit_FConv(Primitive& inPrimitive)
{
InsnFloatMemory *loadInsn;
// Fetch input operand from memory and push it on the FPU stack
switch (inPrimitive.nthInputVariable(0).getKind()) {
case vkFloat:
loadInsn = new InsnFloatMemory(&inPrimitive, mPool, fld32, 1, 1);
useProducer(inPrimitive.nthInputVariable(0), *loadInsn, 0, vrcFloat);
break;
case vkDouble:
loadInsn = new InsnFloatMemory(&inPrimitive, mPool, fld64, 1, 1);
useProducer(inPrimitive.nthInputVariable(0), *loadInsn, 0, vrcDouble);
break;
case vkInt:
{
InsnDoubleOpDir& copyInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegDirect, atRegAllocStackSlot, 1, 1);
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0);
VirtualRegister& tmp = defineTemporary(copyInsn, 0, vrcStackSlot);
loadInsn = new InsnFloatMemory(&inPrimitive, mPool, fild32, 1, 1);
useTemporaryVR(*loadInsn, tmp, 0, vrcStackSlot);
}
break;
case vkLong:
{
InsnDoubleOpDir& copyInsnHi = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegDirect, atRegAllocStackSlotHi32, 1, 1);
useProducer(inPrimitive.nthInputVariable(0), copyInsnHi, 0, vrcInteger, vidHigh);
VirtualRegister& tmp64 = defineTemporary(copyInsnHi, 0, vrcStackSlot);
InsnDoubleOpDir& copyInsnLo = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegDirect, atRegAllocStackSlot, 2, 1);
useProducer(inPrimitive.nthInputVariable(0), copyInsnLo, 0, vrcInteger, vidLow);
useTemporaryVR(copyInsnLo, tmp64, 1);
InstructionDefine& orderStoreLoad = defineTemporaryOrder(copyInsnLo, 0);
loadInsn = new InsnFloatMemory(&inPrimitive, mPool, fild64, 2, 1);
useTemporaryVR(*loadInsn, tmp64, 0, vrcStackSlot);
useTemporaryOrder(*loadInsn, orderStoreLoad, 1);
}
break;
default:
// Absence of default case generates gcc warnings.
break;
}
InstructionDefine& order = defineTemporaryOrder(*loadInsn, 0);
// Store value from top of FPU stack into memory
ValueKind vk = inPrimitive.getKind();
switch (vk) {
case vkFloat:
{
// Pop result from FPU stack and store into memory as 32-bit float
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fstp32, 1, 1);
useTemporaryOrder(storeInsn, order, 0);
defineProducer(inPrimitive, storeInsn, 0, vrcFloat);
}
break;
case vkDouble:
{
// Pop result from FPU stack and store into memory as 64-bit double
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fstp64, 1, 1);
useTemporaryOrder(storeInsn, order, 0);
defineProducer(inPrimitive, storeInsn, 0, vrcDouble);
}
break;
case vkInt:
case vkLong:
{
/* Rounding is controlled by the RC flag in the FPU. Round-to-nearest is the desired rounding mode for
all floating-point instructions *except* conversions from floating-point types to integer types, in
which case round-towards-zero (truncation) is mandated. Rather than temporarily changing the RC flag
for all such conversions, we achieve the equivalent result by subtracting or adding 0.5 to the value
before rounding, i.e.
truncate(x) <==> round(x + sign(x) * 0.5)
FIXME - we still don't handle out-of-range inputs and NaNs per the Java spec.
*/
// Store the 32-bit representation of the floating-point input operand into memory so that we can extract its sign.
InsnFloatMemory& storeInsn1 = *new InsnFloatMemory(&inPrimitive, mPool, fst32, 1, 1);
useTemporaryOrder(storeInsn1, order, 0);
VirtualRegister& tmpVR1 = defineTemporary(storeInsn1, 0, vrcStackSlot);
// Extract the sign bit of the input operand
x86Instruction& andInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, iaAndImm, 0x80000000, atRegAllocStackSlot, 1, 1);
useTemporaryVR(andInsn, tmpVR1, 0, vrcStackSlot);
redefineTemporary(andInsn, tmpVR1, 0, vrcStackSlot);
// Generate 0.5 * sign(input)
const float half = 0.5;
x86Instruction& orInsn = *new(mPool) x86Instruction(&inPrimitive, mPool, iaOrImm, *(Uint32*)&half, atRegAllocStackSlot, 1, 1);
useTemporaryVR(orInsn, tmpVR1, 0, vrcStackSlot);
redefineTemporary(orInsn, tmpVR1, 0, vrcStackSlot);
// Subtract 0.5 * sign(input) from input operand
InsnFloatMemory& subInsn = *new InsnFloatMemory(&inPrimitive, mPool, fsub32, 1, 1);
useTemporaryVR(subInsn, tmpVR1, 0, vrcStackSlot);
redefineTemporaryOrder(subInsn, order, 0);
if (vk == vkInt) {
// Pop result from FPU stack, convert to 32-bit integer, and store into memory
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fistp32, 1, 1);
useTemporaryOrder(storeInsn, order, 0);
// All transfers from the FPU must go through memory, so make a copy from the memory location
// to the integer register destination.
InsnDoubleOpDir& copyInsn = copyFromFloatToIntegerRegister(inPrimitive, storeInsn);
defineProducer(inPrimitive, copyInsn, 0);
} else { // vkLong
// Pop result from FPU stack, convert to 64-bit integer, and store into memory
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fistp64, 1, 1);
useTemporaryOrder(storeInsn, order, 0);
VirtualRegister& tmp64 = defineTemporary(storeInsn, 0, vrcStackSlot); // 64-bit integer stack slot
// Copy high 32-bits from memory to integer register
InsnDoubleOpDir& copyInsnHi = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegAllocStackSlotHi32, atRegDirect, 1, 1);
useTemporaryVR(copyInsnHi, tmp64, 0, vrcStackSlot);
defineProducer(inPrimitive, copyInsnHi, 0, vrcInteger, vidHigh);
// Copy low 32-bits from memory to integer register
InsnDoubleOpDir& copyInsnLo = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegAllocStackSlot, atRegDirect, 1, 1);
useTemporaryVR(copyInsnLo, tmp64, 0, vrcStackSlot);
defineProducer(inPrimitive, copyInsnLo, 0, vrcInteger, vidLow);
}
}
break;
default:
// Absence of default case generates gcc warnings.
assert(0);
break;
}
}
//====================================================================================================
// Floating-point function-call glue
// Obtain the 32-bit float return value of a function call
void x86Win32Emitter::
emit_CallReturnF(InsnUseXDefineYFromPool& callInsn, DataNode& callPrimitive, DataNode& returnValProducer)
{
InstructionDefine& define = defineTemporaryOrder(callInsn, 1);
// Pop result from FPU stack and store into memory as 32-bit float
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&callPrimitive, mPool, fstp32, 1, 1);
useTemporaryOrder(storeInsn, define, 0);
defineProducer(returnValProducer, storeInsn, 0, vrcFloat);
}
// Obtain the 64-bit double return value of a function call
void x86Win32Emitter::
emit_CallReturnD(InsnUseXDefineYFromPool& callInsn, DataNode& callPrimitive, DataNode& returnValProducer)
{
InstructionDefine& define = defineTemporaryOrder(callInsn, 1);
// Pop result from FPU stack and store into memory as 64-bit double
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&callPrimitive, mPool, fstp64, 1, 1);
useTemporaryOrder(storeInsn, define, 0);
defineProducer(returnValProducer, storeInsn, 0, vrcDouble);
}
// Retrieve a 32-bit float argument from the call stack
void x86Win32Emitter::
emit_ArgF(PrimArg& arg, InstructionDefine& order, int curStackOffset)
{
InsnDoubleOpDir& loadParam = *new(mPool) InsnDoubleOpDir(&arg, mPool, raLoadI, curStackOffset, atStackOffset, atRegDirect, 1, 1);
useTemporaryOrder(loadParam, order, 0);
InsnDoubleOpDir& copyInsn = copyFromIntegerRegisterToFloat(arg, loadParam);
defineProducer(arg, copyInsn, 0, vrcFloat);
}
// Retrieve a 64-bit double argument from the call stack
void x86Win32Emitter::
emit_ArgD(PrimArg& arg, InstructionDefine& order, int curStackOffset)
{
InsnFloatMemory& loadInsn = *new InsnFloatMemory(&arg, mPool, fld64, atStackOffset, curStackOffset, 1, 1);
useTemporaryOrder(loadInsn, order, 0);
redefineTemporaryOrder(loadInsn, order, 0);
InsnFloatMemory& copyInsn = *new InsnFloatMemory(&arg, mPool, fstp64, 1, 1);
useTemporaryOrder(copyInsn, order, 0);
defineProducer(arg, copyInsn, 0, vrcDouble);
}
// Push float function return value on top of FPU stack
void x86Win32Emitter::
emit_Result_F(Primitive& inPrimitive)
{
InsnFloatMemory &copyInsn = *new InsnFloatMemory(&inPrimitive, mPool, fld32, 1, 1);
InsnExternalUse& extInsn = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0, vrcFloat);
InstructionDefine& define = defineTemporaryOrder(copyInsn, 0);
useTemporaryOrder(extInsn, define, 0);
inPrimitive.setInstructionRoot(&extInsn);
}
// Push double function return value on top of FPU stack
void x86Win32Emitter::
emit_Result_D(Primitive& inPrimitive)
{
InsnFloatMemory &copyInsn = *new InsnFloatMemory(&inPrimitive, mPool, fld64, 1, 1);
InsnExternalUse& extInsn = *new(mPool) InsnExternalUse(&inPrimitive, mPool, 1);
useProducer(inPrimitive.nthInputVariable(0), copyInsn, 0, vrcDouble);
InstructionDefine& define = defineTemporaryOrder(copyInsn, 0);
useTemporaryOrder(extInsn, define, 0);
inPrimitive.setInstructionRoot(&extInsn);
}
//====================================================================================================
// Comparisons
// Matches pattern: poCatL_I(poFCmp_F(Vfloat, Vfloat))
/* Emits code that follows this pattern:
fld ; push second_arg on FPU stack
fcomp [ebp + xx] ; Load first_arg, set integer condition flags and pop all args
fnstsw ax ; Copy FPU status reg into AX
sahf ; Copy AX into EFLAGS status reg
seta al ; al = (first_arg > second_arg) ? 1 : 0;
setb bl ; bl = ((first_arg < second_arg) || (first_arg == NAN) || (second_arg == NAN)) ? 1 : 0
sub ebx, eax ; Result in lowest byte is -1, 0, or +1
movsx eax, bl ; Sign-extend low byte to 32-bits
(Some changes in operand usage will appear depending on the exact pattern of primitives being matched.)
*/
void x86Win32Emitter::
emit_3wayCmpF(Primitive& inPrimitive, DataNode &first_operand, DataNode &second_operand,
bool negate_result, x86FloatMemoryType load_op, x86FloatMemoryType cmpOp, VRClass vrClass)
{
// Push first operand on FPU stack
InsnFloatMemory& loadInsn2 = *new InsnFloatMemory(&inPrimitive, mPool, load_op, 1, 1);
useProducer(first_operand, loadInsn2, 0, vrClass);
InstructionDefine& order = defineTemporaryOrder(loadInsn2, 0);
// Set FPU status flags
// FIXME - Should this define a condition-flag edge ? There really should be separate
// edge types for integer and FPU condition codes.
InsnFloatMemory& cmpInsn = *new InsnFloatMemory(&inPrimitive, mPool, cmpOp, 2, 1);
useProducer(second_operand, cmpInsn, 0, vrClass);
useTemporaryOrder(cmpInsn, order, 1);
redefineTemporaryOrder(cmpInsn, order, 0);
// Copy FPU status flags to AX register
InsnFloatReg& copyFromStatusFlagsInsn = *new InsnFloatReg(&inPrimitive, mPool, fnstsw, 1, 1);
useTemporaryOrder(copyFromStatusFlagsInsn, order, 0);
VirtualRegister& FPUstatus = defineTemporary(copyFromStatusFlagsInsn, 0);
FPUstatus.preColorRegister(x86GPRToColor[EAX]);
// sahf instruction (copy from AX into integer status flags register)
InsnNoArgs& sahfInsn = *new(mPool) InsnNoArgs(&inPrimitive, mPool, opSahf, 1, 1);
useTemporaryVR(sahfInsn, FPUstatus, 0);
sahfInsn.addDefine(0, udCond);
// setnbe instruction
InsnSet& setInsn1 = *new(mPool) InsnSet(&inPrimitive, mPool, ccJNBE, 1, 1);
setInsn1.addUse(0, udCond);
setInsn1.getInstructionUseBegin()[0].src = &sahfInsn; // condition edge
// setb instruction
InsnSet& setInsn2 = *new(mPool) InsnSet(&inPrimitive, mPool, ccJB, 1, 1);
setInsn2.addUse(0, udCond);
setInsn2.getInstructionUseBegin()[0].src = &sahfInsn; // condition edge
VirtualRegister* tmpVR1, *tmpVR2;
if (negate_result) {
tmpVR2 = &defineTemporary(setInsn1, 0); // (first_operand > second_operand) -> tmpVR2
tmpVR1 = &defineTemporary(setInsn2, 0); // ((first_operand < second_operand) ||
// (first_operand == NAN) ||
// (second_operand == NAN)) -> tmpVR1
} else {
tmpVR1 = &defineTemporary(setInsn1, 0); // (first_operand > second_operand) -> tmpVR1
tmpVR2 = &defineTemporary(setInsn2, 0); // ((first_operand < second_operand) ||
// (first_operand == NAN) ||
// (second_operand == NAN)) -> tmpVR2
}
// FIXME - We must store result of SET instruction in either AL, BL, CL, or DL, but there's no
// way to indicate this restriction to the register allocator so, for now, we hard-code the registers
tmpVR1->preColorRegister(x86GPRToColor[EAX]);
tmpVR2->preColorRegister(x86GPRToColor[EBX]);
// sub instruction
InsnDoubleOpDir& subInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raSub);
useTemporaryVR(subInsn, *tmpVR1, 0);
useTemporaryVR(subInsn, *tmpVR2, 1);
redefineTemporary(subInsn, *tmpVR1, 0); // tmpVR1 - tmpVR2 -> tmpVR1
// Upper 24 bits are garbage. Sign-extend byte to 32-bits using movs instruction
InsnDoubleOp& extInsn = *new(mPool) InsnDoubleOp(&inPrimitive, mPool, opMovSxB, atRegDirect, atRegDirect, 1, 1);
useTemporaryVR(extInsn, *tmpVR1, 0);
defineProducer(inPrimitive, extInsn, 0); // exts(tmpVR1) -> result
}
void x86Win32Emitter::
emit_3wayCmpF_G(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(0), cmpPrimitive.nthInputVariable(1),
false, fld32, fcomp32, vrcFloat);
}
void x86Win32Emitter::
emit_3wayCmpF_L(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(1), cmpPrimitive.nthInputVariable(0),
true, fld32, fcomp32, vrcFloat);
}
void x86Win32Emitter::
emit_3wayCmpD_G(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(0), cmpPrimitive.nthInputVariable(1),
false, fld64, fcomp64, vrcDouble);
}
void x86Win32Emitter::
emit_3wayCmpD_L(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(1), cmpPrimitive.nthInputVariable(0),
true, fld64, fcomp64, vrcDouble);
}
void x86Win32Emitter::
emit_3wayCmpCF_G(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(1), cmpPrimitive.nthInputVariable(0),
false, fld32, fcomp32, vrcFloat);
}
void x86Win32Emitter::
emit_3wayCmpCF_L(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(0), cmpPrimitive.nthInputVariable(1),
true, fld32, fcomp32, vrcFloat);
}
void x86Win32Emitter::
emit_3wayCmpCD_G(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(1), cmpPrimitive.nthInputVariable(0),
false, fld64, fcomp64, vrcDouble);
}
void x86Win32Emitter::
emit_3wayCmpCD_L(Primitive& inPrimitive)
{
Primitive& cmpPrimitive = Primitive::cast(inPrimitive.nthInputVariable(0));
emit_3wayCmpF(inPrimitive, cmpPrimitive.nthInputVariable(0), cmpPrimitive.nthInputVariable(1),
true, fld64, fcomp64, vrcDouble);
}
//====================================================================================================
// Constants
// Generate 32-bit float constant
void x86Win32Emitter::
emit_LoadConstant_F(Primitive& inPrimitive)
{
Uint32 constant = (*static_cast<const PrimConst *>(&inPrimitive)).value.i;
x86Instruction* newInsn;
if(constant == 0)
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, srmMoveImm0, 0, 0, 1);
else
newInsn = new(mPool) x86Instruction(&inPrimitive, mPool, ceMoveImm, constant, atRegDirect, 0, 1);
defineProducer(inPrimitive, copyFromIntegerRegisterToFloat(inPrimitive, *newInsn), 0, vrcFloat); // result
}
// Generate 64-bit double constant
// FIXME: Need to create an in-memory literal pool for storing double constants, rather than using immediate instructions
void x86Win32Emitter::
emit_LoadConstant_D(Primitive& inPrimitive)
{
Flt64 constant = (*static_cast<const PrimConst *>(&inPrimitive)).value.d;
// Store 64-bit double constant in literal pool
// FIXME - We should have a literal pool for each method to store in-memory constants
// and which can be released when the method is discarded.
Flt64* literalPoolEntry = (Flt64*)malloc(sizeof(Flt64));
*literalPoolEntry = constant;
// Fetch from memory and temporarily push 64-bit double on the FPU stack
InsnFloatMemory &loadInsn = *new InsnFloatMemory(&inPrimitive, mPool, fld64, atAbsoluteAddress, (Uint32)literalPoolEntry, 0, 1);
InstructionDefine& order = defineTemporaryOrder(loadInsn, 0);
// Pop 64-bit double from FPU stack and store into double variable
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fstp64, 1, 1);
useTemporaryOrder(storeInsn, order, 0);
defineProducer(inPrimitive, storeInsn, 0, vrcDouble); // result
}
//====================================================================================================
// Floating-point memory operations
void x86Win32Emitter::
emit_Ld_F(Primitive& inPrimitive)
{
// Load 32-bit float into an integer register
InsnDoubleOpDir& loadInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raLoadI, atRegisterIndirect, atRegDirect);
useProducer(inPrimitive.nthInputVariable(0), loadInsn, 1); // memory edge
useProducer(inPrimitive.nthInputVariable(1), loadInsn, 0); // address
// Store into 32-bit float variable
InsnDoubleOpDir& storeInsn = copyFromIntegerRegisterToFloat(inPrimitive, loadInsn);
defineProducer(inPrimitive, storeInsn, 0, vrcFloat); // result
}
void x86Win32Emitter::
emit_Ld_D(Primitive& inPrimitive)
{
// Fetch from memory and temporarily push 64-bit double on the FPU stack
InsnFloatMemory &loadInsn = *new InsnFloatMemory(&inPrimitive, mPool, fld64, atRegisterIndirect, 2, 1);
useProducer(inPrimitive.nthInputVariable(0), loadInsn, 1); // memory edge
useProducer(inPrimitive.nthInputVariable(1), loadInsn, 0); // address
InstructionDefine& order = defineTemporaryOrder(loadInsn, 0);
// Pop 64-bit double from FPU stack
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fstp64, 1, 1);
useTemporaryOrder(storeInsn, order, 0);
defineProducer(inPrimitive, storeInsn, 0, vrcDouble); // result
}
void x86Win32Emitter::
emit_St_F(Primitive& inPrimitive)
{
// Load 32-bit float into an integer register
InsnDoubleOpDir& loadInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raCopyI, atRegAllocStackSlot, atRegDirect, 1, 1);
useProducer(inPrimitive.nthInputVariable(2), loadInsn, 0); // data
VirtualRegister& floatVal = defineTemporary(loadInsn, 0); // intermediate output
// Store temporary integer register into indirect register destination
InsnDoubleOpDir& storeInsn = *new(mPool) InsnDoubleOpDir(&inPrimitive, mPool, raStoreI, atRegisterIndirect, atRegDirect, 3, 1);
useProducer(inPrimitive.nthInputVariable(1), storeInsn, 0); // address
useTemporaryVR(storeInsn, floatVal, 1); // data
useProducer(inPrimitive.nthInputVariable(0), storeInsn, 2); // memory edge in
defineProducer(inPrimitive, storeInsn, 0); // memory edge out
}
void x86Win32Emitter::
emit_St_D(Primitive& inPrimitive)
{
// Temporarily push 64-bit double on the FPU stack
InsnFloatMemory& loadInsn = *new InsnFloatMemory(&inPrimitive, mPool, fld64, 1, 1);
useProducer(inPrimitive.nthInputVariable(2), loadInsn, 0, vrcDouble); // data
InstructionDefine& order = defineTemporaryOrder(loadInsn, 0);
// Pop result from FPU stack and store into memory as 64-bit double
InsnFloatMemory& storeInsn = *new InsnFloatMemory(&inPrimitive, mPool, fstp64, atRegisterIndirect, 3, 1);
useProducer(inPrimitive.nthInputVariable(1), storeInsn, 0); // address
useTemporaryOrder(storeInsn, order, 1);
useProducer(inPrimitive.nthInputVariable(0), storeInsn, 2); // memory edge in
defineProducer(inPrimitive, storeInsn, 0); // memory edge out
}

Просмотреть файл

@ -0,0 +1,130 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86Float.h - Floating-point code-generation for x86 processors
//
#ifndef X86_FLOAT_H
#define X86_FLOAT_H
#include "x86Win32Instruction.h"
//-----------------------------------------------------------------------------------------------------------
// Floating-point instructions in which one operand is a memory location.
// If there is a second operand, then it is implicitly the top of the FPU stack.
class InsnFloatMemory :
public x86ArgListInstruction
{
public:
InsnFloatMemory(DataNode* inPrimitive, Pool& inPool, x86FloatMemoryType inOpInfo, int inX, int inY):
x86ArgListInstruction (inPrimitive, inPool, inX, inY )
{
opcodeInfo = &opcodeTable[inOpInfo];
iArgumentList = new x86SingleArgumentList(atRegAllocStackSlot);
}
InsnFloatMemory(DataNode* inPrimitive, Pool& inPool, x86FloatMemoryType inOpInfo, x86ArgumentType argType,
Int32 displacement, int inX, int inY):
x86ArgListInstruction (inPrimitive, inPool, inX, inY )
{
opcodeInfo = &opcodeTable[inOpInfo];
iArgumentList = new x86SingleArgumentList(argType, displacement);
}
InsnFloatMemory(DataNode* inPrimitive, Pool& inPool, x86FloatMemoryType inOpInfo, x86ArgumentType argType,
int inX, int inY):
x86ArgListInstruction (inPrimitive, inPool, inX, inY )
{
opcodeInfo = &opcodeTable[inOpInfo];
iArgumentList = new x86SingleArgumentList(argType);
}
virtual Uint8 opcodeSize() {return 1;}
virtual void formatToMemory(void * /*inStart*/, Uint32 /*inCurOffset*/, MdFormatter& /*inEmitter*/);
// spilling
virtual bool switchUseToSpill(Uint8 /*inWhichUse*/, VirtualRegister &/*inVR*/) { return false; }
virtual bool switchDefineToSpill(Uint8 /*inWhichDefine*/, VirtualRegister &/*inVR*/) { return false; }
// Control Spilling
virtual bool opcodeAcceptsSpill() { return false; }
virtual void switchOpcodeToSpill() { assert(0); }
protected:
x86OpcodeInfo* opcodeInfo;
private:
static x86OpcodeInfo opcodeTable[];
public:
#ifdef DEBUG_LOG
// Debugging Methods
virtual void printOpcode(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-9s", opcodeInfo->oiText)); }
#endif // DEBUG_LOG
};
//-----------------------------------------------------------------------------------------------------------
// Floating-point instructions in which all operands and results are implicitly on the FPU stack
enum x86FloatRegType
{
fucomip,
fneg,
fnstsw
};
class InsnFloatReg :
public InsnUseXDefineYFromPool
{
public:
InsnFloatReg(DataNode* inPrimitive, Pool& inPool, x86FloatRegType inOpInfo, Uint8 inX, Uint8 inY):
InsnUseXDefineYFromPool (inPrimitive, inPool, inX, inY )
{
opcodeInfo = &opcodeTable[inOpInfo];
}
virtual Uint8 opcodeSize() {return 2;}
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return 2; };
virtual void formatToMemory(void * /*inStart*/, Uint32 /*inCurOffset*/, MdFormatter& /*inEmitter*/);
// spilling
virtual bool switchUseToSpill(Uint8 /*inWhichUse*/, VirtualRegister &/*inVR*/) { return false; }
virtual bool switchDefineToSpill(Uint8 /*inWhichDefine*/, VirtualRegister &/*inVR*/) { return false; }
// Control Spilling
virtual bool opcodeAcceptsSpill() { return false; }
virtual void switchOpcodeToSpill() { assert(0); }
protected:
x86OpcodeInfo* opcodeInfo;
private:
static x86OpcodeInfo opcodeTable[];
public:
#ifdef DEBUG_LOG
// Debugging Methods
virtual void printPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-9s", opcodeInfo->oiText)); }
#endif // DEBUG_LOG
};
#endif // X86_FLOAT_H

Просмотреть файл

@ -0,0 +1,236 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: x86Formatter.cpp
//
// Authors: Peter DeSantis
// Simon Holmes a Court
// Scott Silver
//
#include "x86Formatter.h"
#include "FieldOrMethod.h"
#include "MemoryAccess.h"
#include "JavaObject.h"
//-----------------------------------------------------------------------------------------------------------
// Constants
const Uint8 kPush_ebp = 0x55;
const Uint8 kPush_edi = 0x57;
const Uint8 kPush_esi = 0x56;
const Uint8 kPush_ebx = 0x53;
const Uint16 kMov_ebp_esp = 0x8bec;
const Uint16 kSub_esp_Imm8 = 0x83ec; // 8-bit immediate subtract (8-bit val extended to 32-bits)
const Uint16 kSub_esp_Imm32 = 0x81ec; // Signed, 32-bit immediate subtract
const Uint8 kPop_ebp = 0x5d;
const Uint8 kPop_ebx = 0x5b;
const Uint8 kPop_esi = 0x5e;
const Uint8 kPop_edi = 0x5f;
const Uint8 kRet = 0xc3;
const Uint8 kRet_Imm16 = 0xc2;
const Uint16 kMov_esp_ebp = 0x8be5;
//-----------------------------------------------------------------------------------------------------------
// x86Formatter
void x86Formatter::
beginFormatting(const FormattedCodeInfo& inInfo)
{
mFCI = inInfo;
}
void x86Formatter::
initStackFrameInfo()
{
mStackFrameInfo.init(mEmitter.mVRAllocator);
}
void x86Formatter::
calculatePrologEpilog(Method& inMethod, Uint32& outPrologSize, Uint32& outEpilogSize)
{
Uint32 GPRwords = mStackFrameInfo.getNumSavedGPRWords();
Uint32 localStoreBytes = mStackFrameInfo.getLocalStoreSizeBytes();
if(localStoreBytes == 0)
{
mPrologSize_bytes = 3 + GPRwords;
mEpilogSize_bytes = 4 + GPRwords;
}
else {
if (localStoreBytes < 128)
mPrologSize_bytes = 6 + GPRwords;
else
mPrologSize_bytes = 9 + GPRwords;
mEpilogSize_bytes = 6 + GPRwords;
}
// determine how many words were passed to us, so the epilog can clean up the stack
const Signature& ourSignature = inMethod.getSignature();
const int numArgs = ourSignature.nArguments;
const Type** ourArgs = ourSignature.argumentTypes;
mNumberOfArgumentWords = 0;
for(int i = 0; i < numArgs; i++)
mNumberOfArgumentWords += nTypeKindSlots(ourArgs[i]->typeKind);
outPrologSize = mPrologSize_bytes;
outEpilogSize = mEpilogSize_bytes;
}
void x86Formatter::
formatPrologToMemory(void* inWhere)
{
Uint8* where = (uint8*)inWhere;
// push ebp
*where++ = kPush_ebp;
//mov ebp, esp
writeBigHalfwordUnaligned(where, kMov_ebp_esp);
where += 2;
// reserve local store space
// sub esp, localstore
Uint32 localStoreBytes = mStackFrameInfo.getLocalStoreSizeBytes();
if (localStoreBytes) {
if (localStoreBytes < 128)
{
writeBigHalfwordUnaligned(where, kSub_esp_Imm8);
where += 2;
*where++ = localStoreBytes;
}
else
{
writeBigHalfwordUnaligned(where, kSub_esp_Imm32);
where += 2;
writeLittleWordUnaligned(where, localStoreBytes);
where += 4;
}
}
// save GPRs -- FIX change to bitfields sometime
Uint32 GPRwords = mStackFrameInfo.getNumSavedGPRWords();
if(GPRwords > 2)
*where++ = kPush_edi;
if(GPRwords > 1)
*where++ = kPush_esi;
if(GPRwords > 0)
*where++ = kPush_ebx;
}
void x86Formatter::
formatEpilogToMemory(void* inWhere)
{
Uint8* where = (uint8*)inWhere;
// restore GPRs -- FIX change to bitfields sometime
Uint32 GPRwords = mStackFrameInfo.getNumSavedGPRWords();
if(GPRwords > 0)
*where++ = kPop_ebx;
if(GPRwords > 1)
*where++ = kPop_esi;
if(GPRwords > 2)
*where++ = kPop_edi;
// mov esp, ebp
Uint32 localStoreBytes = mStackFrameInfo.getLocalStoreSizeBytes();
if(localStoreBytes != 0)
{
writeBigHalfwordUnaligned(where, kMov_esp_ebp);
where+=2;
}
// pop ebp
*where++ = kPop_ebp;
// return cleaning the stack of passed in arguments
if(mNumberOfArgumentWords != 0)
{
*where++ = kRet_Imm16;
writeLittleHalfwordUnaligned(where, mNumberOfArgumentWords * 4);
}
else
{
*where = kRet;
}
}
Uint8* x86Formatter::
createTransitionVector(const FormattedCodeInfo& inInfo)
{
return inInfo.methodStart;
}
Uint8* x86Formatter::
getMethodBegin()
{
return mFCI.methodStart;
}
//-----------------------------------------------------------------------------------------------------------
// Debugging
#ifdef DEBUG_LOG
#include "XDisAsm.h"
#define USING_X86_DISASSEMBLER
const int kMaxDissasemblyBytes = 8; // maximum number of bytes to dump per instruction
// Function: disassemble1
void*
disassemble1(LogModuleObject &f, void* inFrom)
{
#ifdef USING_X86_DISASSEMBLER
char* disasmText;
char* startAddr = (char*)inFrom;
char* curAddr = startAddr;
disasmText = disasmx86( 0,
&curAddr,
curAddr + 32,
kDisAsmFlag32BitSegments);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("0x%p: ", inFrom));
// print memory dump
Uint8 numBytes = (Uint8)curAddr - (Uint8)startAddr;
for(int i = 0; i < kMaxDissasemblyBytes; i++)
{
if (i < numBytes) {
Uint8 address= ((Uint8*)startAddr)[i];
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%x%x ", address/16, address%16));
}
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" "));
}
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" %s\n", disasmText));
return (curAddr);
#else
f = NULL; inFrom = NULL;
return NULL;
#endif
}
#endif // DEBUG_LOG

Просмотреть файл

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: x86Formatter.h
//
// Authors: Peter DeSantis
// Simon Holmes a Court
// Scott Silver
//
#ifndef X86_FORMATTER
#define X86_FORMATTER
#include "Fundamentals.h"
#include "FormatStructures.h" // for FCI, StackFrameInfo
#include "x86Win32Emitter.h" // temp?
const int kStackSlotSize = 8;
//-----------------------------------------------------------------------------------------------------------
// x86StackFrameInfo
class x86StackFrameInfo :
public StackFrameInfo
{
public:
x86StackFrameInfo() { }
void init(VirtualRegisterManager& inVRManager)
{
// eventually the register allocator will tell us all this information
numSavedGPRs = 3;
numSavedFPRs = 0;
numMonitorSlots = 0;
localStore_bytes = inVRManager.nUsedStackSlots * kStackSlotSize;
StackFrameInfo::init(inVRManager);
}
// return number of bytes than EBP of the stack slot
Int32 getStackSlotOffset(VirtualRegister& inVr)
{
assert(hasBeenInited);
assert(inVr.getClass() == StackSlotRegister);
return (inVr.getColor() * - kStackSlotSize) - kStackSlotSize;
}
private:
};
//-----------------------------------------------------------------------------------------------------------
// x86Formatter
class x86Formatter
{
protected:
Uint16 mNumberOfArgumentWords;
Uint32 mFrameSize_words;
Uint32 mPrologSize_bytes;
Uint32 mEpilogSize_bytes;
x86StackFrameInfo mStackFrameInfo;
// later should be object, not pointer
FormattedCodeInfo mFCI; // cached format info
public:
// fields
const MdEmitter& mEmitter;
// methods
x86Formatter(const MdEmitter& inEmitter) : mEmitter(inEmitter) { }
void calculatePrologEpilog(Method& /*inMethod*/, Uint32& outPrologSize, Uint32& outEpilogSize);
void formatEpilogToMemory(void* inWhere);
void formatPrologToMemory(void* inWhere);
void beginFormatting(const FormattedCodeInfo& inInfo);
void endFormatting(const FormattedCodeInfo& /*inInfo*/) { }
void calculatePrePostMethod(Method& /*inMethod*/, Uint32& outPreMethodSize, Uint32& outPostMethodSize) { outPreMethodSize = outPostMethodSize = 0; }
void formatPostMethodToMemory(void* /*inWhere*/, const FormattedCodeInfo& /*inInfo*/) { }
void formatPreMethodToMemory(void* /*inWhere*/, const FormattedCodeInfo& /*inInfo*/) { }
// stack frame stuff
void initStackFrameInfo();
StackFrameInfo& getStackFrameInfo() {return mStackFrameInfo; }
Int32 getStackSlotOffset(VirtualRegister& inVr) { return mStackFrameInfo.getStackSlotOffset(inVr); }
Uint8* createTransitionVector(const FormattedCodeInfo& inInfo);
Uint8* getMethodBegin();
};
#ifdef DEBUG_LOG
void* disassemble1(LogModuleObject &f, void* inFrom);
#endif
#endif // X86_FORMATTER

Просмотреть файл

@ -0,0 +1,593 @@
/* -*- Mode: asm; tab-width:4; truncate-lines:t -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
.file "x86Linux.S"
#define ALIGN .align 16
#define SYMBOL_NAME(name) name
#define SYMBOL_NAME_LABEL(name) name##:
#define GLOBAL_ENTRY_START(name) \
ALIGN; \
.globl SYMBOL_NAME(name); \
.type SYMBOL_NAME(name),@function; \
SYMBOL_NAME_LABEL(name)
#define GLOBAL_ENTRY_END(name) \
SYMBOL_NAME_LABEL(.L##name); \
.size SYMBOL_NAME(name),SYMBOL_NAME(.L##name)-SYMBOL_NAME(name)
GLOBAL_ENTRY_START(staticCompileStub)
push %eax /* Save all volatiles */
push %ebx
push %ecx
push %edx
push 20(%esp) /* Push the second argument to compileAndBackPatchMethod (return address) */
push 20(%esp) /* Push the first argument to compileAndBackPatchMethod (cacheEntry) */
call compileAndBackPatchMethod
pop %edx /* Remove passes arguments */
pop %edx /* Remove passes arguments */
mov %eax, 16(%esp) /* Overwrite cacheEntry with function address */
pop %edx /* Restore volatiles */
pop %ecx
pop %ebx
pop %eax
ret /* Jump to function leaving the return address at the top of the stack */
GLOBAL_ENTRY_END(staticCompileStub)
GLOBAL_ENTRY_START(compileStub)
push 0xefbeadde /* This is a dummy immediate that will be filled in by */
jmp staticCompileStub /* generateCompileStub with the cacheEntry */
GLOBAL_ENTRY_END(compileStub)
/*
* 64bit Arithmetic Support Functions
*
* x86Extract64Bit
*
* Origin: Simon
* Purpose: signed right-aligned field extraction
* In: 64 bit source (on stack)
* 32 bit extraction size (on stack)
* Out: 64 bit result
* Note: Only works in range 1 <= b <= 63, b is extraction amount
*/
GLOBAL_ENTRY_START(x86Extract64Bit)
mov 4(%esp),%eax /* load low byte of a */
mov 12(%esp),%ecx /*load shift amount */
cmp $0x20,%ecx
jg greater32
/* extract <= than 32 bits
* shift amount = 32 - extract
*/
neg %ecx
add $0x20,%ecx /* ecx = 32 - extract */
shl %cl,%eax
sar %cl,%eax
cdq /* sign extend into EDX:EAX */
ret $12
greater32:
/* ext > 32 bits
* shift amount = 64 - extract
*/
mov 8(%esp),%edx /* load high byte of a */
neg %ecx
add $0x40,%ecx /* ecx = 64 - extract */
shl %cl,%edx
sar %cl,%edx
ret $12
GLOBAL_ENTRY_END(x86Extract64Bit)
/*
* 3WayCompare
*
* Origin: Symantec JIT
* Purpose: compare two longs
* In: two longs on the stack
* Out: depends on condition flags:
* less = -1
* equal = 0
* greater = 1
*/
GLOBAL_ENTRY_START(x86ThreeWayCMP_L)
/* edx:eax is tos, ecx:ebx is nos */
mov 8(%esp),%ecx
mov 16(%esp),%edx
cmp %edx,%ecx
jl lcmp_m1
jg lcmp_1
mov 4(%esp),%ecx
mov 12(%esp),%edx
cmp %edx,%ecx
ja lcmp_1
mov $0,%eax
jb lcmp_m1
ret $16
.align 4
lcmp_m1:
mov $-1,%eax
ret $16
.align 4
lcmp_1:
mov $1,%eax
ret $16
GLOBAL_ENTRY_END(x86ThreeWayCMP_L)
/*
* llmul
*
* Origin: Intel Code (via MSDev)
* Purpose: long multiply (same for signed/unsigned)
* In: args are passed on the stack:
* 1st pushed: multiplier (QWORD)
* 2nd pushed: multiplicand (QWORD)
* Out: EDX:EAX - product of multiplier and multiplicand
* Note: parameters are removed from the stack
* Uses: ECX
*/
GLOBAL_ENTRY_START(x86Mul64Bit)
/* A*B = (A.lo * B.lo) + (A.lo * B.hi) + (B.lo * A.hi) ??? */
mov 8(%esp),%eax /* A.hi */
mov 16(%esp),%ecx /* B.hi */
or %eax,%ecx /* test for both hiwords zero */
mov 12(%esp),%ecx /* B.lo */
jnz hard
/* easy case
* both are zero, just mult ALO and BLO
*/
mov 4(%esp),%eax /* A.lo */
mul %ecx /* A.lo * B.lo */
ret $16 /* callee restores the stack */
/* hard case */
hard:
push %ebx
mul %ecx /* A.hi * B.lo */
mov %eax,%ebx /* save result */
mov 8(%esp),%eax /* A.lo */
mull 14(%esp) /* A.lo * B.hi */
add %eax,%ebx /* ebx = ((A.lo * B.hi) + (A.hi * B.lo)) */
mov 8(%esp),%eax /* A.lo */
mul %ecx /* edx:eax = A.lo * B.lo */
add %ebx,%edx /* now edx has all the LO*HI stuff */
pop %ebx
ret $16 /* callee restores the stack */
GLOBAL_ENTRY_END(x86Mul64Bit)
/*
* lldiv
*
* Origin: Intel Code (via MSDev)
* Purpose: signed long divide
* In: args are passed on the stack:
* 1st pushed: divisor (QWORD)
* 2nd pushed: dividend (QWORD)
* Out: EDX:EAX contains the quotient (dividend/divisor)
* Note: parameters are removed from the stack
* Uses: ECX
*/
GLOBAL_ENTRY_START(x86Div64Bit)
push %edi
push %esi
push %ebx
/* Determine sign of the result (%edi = 0 if result is positive, non-zero
* otherwise) and make operands positive.
*/
xor %edi,%edi /* result sign assumed positive */
mov 20(%esp),%eax /* hi word of a */
or %eax,%eax /* test to see if signed */
jge L1 /* skip rest if a is already positive */
inc %edi /* complement result sign flag */
mov 16(%esp),%edx /* lo word of a */
neg %eax /* make a positive */
neg %edx
sbb $0,%eax
mov %eax,20(%esp) /* save positive value */
mov %edx,16(%esp)
L1:
mov 28(%esp),%eax /* hi word of b */
or %eax,%eax /* test to see if signed */
jge L2 /* skip rest if b is already positive */
inc %edi /* complement the result sign flag */
mov 24(%esp),%edx /* lo word of a */
neg %eax /* make b positive */
neg %edx
sbb $0,%eax
mov %eax,28(%esp) /* save positive value */
mov %edx,24(%esp)
L2:
/* Now do the divide. First look to see if the divisor is less than 4194304K.
* If so, then we can use a simple algorithm with word divides, otherwise
* things get a little more complex.
* NOTE - %eax currently contains the high order word of DVSR
*/
or %eax,%eax /* check to see if divisor < 4194304K */
jnz L3 /* nope, gotta do this the hard way */
mov 24(%esp),%ecx /* load divisor */
mov 20(%esp),%eax /* load high word of dividend */
xor %edx,%edx
div %ecx /* %eax <- high order bits of quotient */
mov %eax,%ebx /* save high bits of quotient */
mov 16(%esp),%eax /* %edx:%eax <- remainder:lo word of dividend */
div %ecx /* %eax <- low order bits of quotient */
mov %ebx,%edx /* %edx:%eax <- quotient */
jmp L4 /* set sign, restore stack and return */
/* Here we do it the hard way. Remember, %eax contains the high word of DVSR */
L3:
mov %eax,%ebx /* %ebx:ecx <- divisor */
mov 24(%esp),%ecx
mov 20(%esp),%edx /* %edx:%eax <- dividend */
mov 16(%esp),%eax
L5:
shr $1,%ebx /* shift divisor right one bit */
rcr $1,%ecx
shr $1,%edx /* shift dividend right one bit */
rcr $1,%eax
or %ebx,%ebx
jnz L5 /* loop until divisor < 4194304K */
div %ecx /* now divide, ignore remainder */
mov %eax,%esi /* save quotient */
/* We may be off by one, so to check, we will multiply the quotient
* by the divisor and check the result against the orignal dividend
* Note that we must also check for overflow, which can occur if the
* dividend is close to 2**64 and the quotient is off by 1.
*/
mull 28(%esp) /* QUOT * HIWORD(DVSR) */
mov %eax,%ecx
mov 24(%esp),%eax
mul %esi /* QUOT * LOWORD(DVSR) */
add %ecx,%edx /* %EDX:%EAX = QUOT * DVSR */
jc L6 /* carry means Quotient is off by 1 */
/* do long compare here between original dividend and the result of the
* multiply in %edx:%eax. If original is larger or equal, we are ok, otherwise
* subtract one (1) from the quotient.
*/
cmp 20(%esp),%edx /* compare hi words of result and original */
ja L6 /* if result > original, do subtract */
jb L7 /* if result < original, we are ok */
cmp 16(%esp),%eax /* hi words are equal, compare lo words */
jbe L7 /* if less or equal we are ok, else subtract */
L6:
dec %esi /* subtract 1 from quotient */
L7:
xor %edx,%edx /* %edx:%eax <- quotient */
mov %esi,%eax
/* Just the cleanup left to do. %edx:%eax contains the quotient. Set the sign
* according to the save value, cleanup the stack, and return.
*/
L4:
dec %edi /* check to see if result is negative */
jnz L8 /* if %EDI == 0, result should be negative */
neg %edx /* otherwise, negate the result */
neg %eax
sbb $0,%edx
/* Restore the saved registers and return. */
L8:
pop %ebx
pop %esi
pop %edi
ret $16
GLOBAL_ENTRY_END(x86Div64Bit)
/*
* llrem
*
* Origin: MSDev
* Purpose: signed long remainder
* In: args are passed on the stack:
* 1st pushed: divisor (QWORD)
* 2nd pushed: dividend (QWORD)
* Out: %EDX:%EAX contains the quotient (dividend/divisor)
* Note: parameters are removed from the stack
* Uses: %ECX
*/
GLOBAL_ENTRY_START(x86Mod64Bit)
push %ebx
push %edi
/* Determine sign of the result (%edi = 0 if result is positive, non-zero
* otherwise) and make operands positive.
*/
xor %edi,%edi /* result sign assumed positive */
mov 16(%esp),%eax /* hi word of a */
or %eax,%eax /* test to see if signed */
jge LL1 /* skip rest if a is already positive */
inc %edi /* complement result sign flag bit */
mov 12(%esp),%edx /* lo word of a */
neg %eax /* make a positive */
neg %edx
sbb $0,%eax
mov %eax,16(%esp) /* save positive value */
mov %edx,12(%esp)
LL1:
mov 24(%esp),%eax /* hi word of b */
or %eax,%eax /* test to see if signed */
jge LL2 /* skip rest if b is already positive */
mov 20(%esp),%edx /* lo word of b */
neg %eax /* make b positive */
neg %edx
sbb $0,%eax
mov %eax,24(%esp) /* save positive value */
mov %edx,20(%esp)
LL2:
/* Now do the divide. First look to see if the divisor is less than 4194304K.
* If so, then we can use a simple algorithm with word divides, otherwise
* things get a little more complex.
* NOTE - %eax currently contains the high order word of DVSR
*/
or %eax,%eax /* check to see if divisor < 4194304K */
jnz LL3 /* nope, gotta do this the hard way */
mov 20(%esp),%ecx /* load divisor */
mov 16(%esp),%eax /* load high word of dividend */
xor %edx,%edx
div %ecx /* %edx <- remainder */
mov 12(%esp),%eax /* %edx:%eax <- remainder:lo word of dividend */
div %ecx /* %edx <- final remainder */
mov %edx,%eax /* %edx:%eax <- remainder */
xor %edx,%edx
dec %edi /* check result sign flag */
jns LL4 /* negate result, restore stack and return */
jmp LL8 /* result sign ok, restore stack and return */
/* Here we do it the hard way. Remember, %eax contains the high word of DVSR */
LL3:
mov %eax,%ebx /* %ebx:%ecx <- divisor */
mov 20(%esp),%ecx
mov 16(%esp),%edx /* %edx:%eax <- dividend */
mov 12(%esp),%eax
LL5:
shr $1,%ebx /* shift divisor right one bit */
rcr $1,%ecx
shr $1,%edx /* shift dividend right one bit */
rcr $1,%eax
or %ebx,%ebx
jnz LL5 /* loop until divisor < 4194304K */
div %ecx /* now divide, ignore remainder */
/* We may be off by one, so to check, we will multiply the quotient
* by the divisor and check the result against the orignal dividend
* Note that we must also check for overflow, which can occur if the
* dividend is close to 2**64 and the quotient is off by 1.
*/
mov %eax,%ecx /* save a copy of quotient in %ECX */
mull 24(%esp)
xchg %eax,%ecx /* save product, get quotient in %EAX */
mull 20(%esp)
add %ecx,%edx /* %EDX:%EAX = QUOT * DVSR */
jc LL6 /* carry means Quotient is off by 1 */
/* do long compare here between original dividend and the result of the
* multiply in %edx:%eax. If original is larger or equal, we are ok, otherwise
* subtract the original divisor from the result.
*/
cmp 16(%esp),%edx /* compare hi words of result and original */
ja LL6 /* if result > original, do subtract */
jb LL7 /* if result < original, we are ok */
cmp 12(%esp),%eax /* hi words are equal, compare lo words */
jbe LL7 /* if less or equal we are ok, else subtract */
LL6:
sub 20(%esp),%eax /* subtract divisor from result */
sbb 24(%esp),%edx
LL7:
/* Calculate remainder by subtracting the result from the original dividend.
* Since the result is already in a register, we will do the subtract in the
* opposite direction and negate the result if necessary.
*/
sub 12(%esp),%eax /* subtract dividend from result */
sbb 16(%esp),%edx
/* Now check the result sign flag to see if the result is supposed to be positive
* or negative. It is currently negated (because we subtracted in the 'wrong'
* direction), so if the sign flag is set we are done, otherwise we must negate
* the result to make it positive again.
*/
dec %edi /* check result sign flag */
jns LL8 /* result is ok, restore stack and return */
LL4:
neg %edx /* otherwise, negate the result */
neg %eax
sbb $0,%edx
/* Just the cleanup left to do. %edx:%eax contains the quotient.
* Restore the saved registers and return.
*/
LL8:
pop %edi
pop %ebx
ret $16
GLOBAL_ENTRY_END(x86Mod64Bit)
/*
* llshl
*
* Origin: MSDev. modified
* Purpose: long shift left
* In: args are passed on the stack: (FIX make fastcall)
* 1st pushed: amount (int)
* 2nd pushed: source (long)
* Out: %EDX:%EAX contains the result
* Note: parameters are removed from the stack
* Uses: %ECX, destroyed
*/
GLOBAL_ENTRY_START(x86Shl64Bit)
/* prepare from stack */
mov 4(%esp),%eax
mov 8(%esp),%edx
mov 12(%esp),%ecx
cmp $64,%cl
jae RETZERO
/* Handle shifts of between 0 and 31 bits */
cmp $32,%cl
jae MORE32
shld %eax,%edx
shl %cl,%eax
ret $12
/* Handle shifts of between 32 and 63 bits */
MORE32:
mov %eax,%edx
xor %eax,%eax
and $31,%cl
shl %cl,%edx
ret $12
/* return 0 in %edx:%eax */
RETZERO:
xor %eax,%eax
xor %edx,%edx
ret $12
GLOBAL_ENTRY_END(x86Shl64Bit)
/*
* llshr
*
* Origin: MSDev. modified
* Purpose: long shift right
* In: args are passed on the stack: (FIX make fastcall)
* 1st pushed: amount (int)
* 2nd pushed: source (long)
* Out: %EDX:%EAX contains the result
* Note: parameters are removed from the stack
* Uses: %ECX, destroyed
*/
GLOBAL_ENTRY_START(x86Shr64Bit)
/* prepare from stack */
mov 4(%esp),%eax
mov 8(%esp),%edx
mov 12(%esp),%ecx
cmp $64,%cl
jae RRETZERO
/* Handle shifts of between 0 and 31 bits */
cmp $32,%cl
jae MMORE32
shrd %edx,%eax
shr %cl,%edx
ret $12
/* Handle shifts of between 32 and 63 bits */
MMORE32:
mov %edx,%eax
xor %edx,%edx
and $31,%cl
shr %cl,%eax
ret $12
/* return 0 in %edx:%eax */
RRETZERO:
xor %eax,%eax
xor %edx,%edx
ret $12
GLOBAL_ENTRY_END(x86Shr64Bit)
/*
* llsar
*
* Origin: MSDev. modified
* Purpose: long shift right signed
* In: args are passed on the stack: (FIX make fastcall)
* 1st pushed: amount (int)
* 2nd pushed: source (long)
* Out: %EDX:%EAX contains the result
* Note: parameters are removed from the stack
* Uses: %ECX, destroyed
*/
GLOBAL_ENTRY_START(x86Sar64Bit)
/* prepare from stack */
mov 4(%esp),%eax
mov 8(%esp),%edx
mov 12(%esp),%ecx
/* Handle shifts of 64 bits or more (if shifting 64 bits or more, the result */
/* depends only on the high order bit of %edx). */
cmp $64,%cl
jae RETSIGN
/* Handle shifts of between 0 and 31 bits */
cmp $32,%cl
jae MMMORE32
shrd %edx,%eax
sar %cl,%edx
ret $12
/* Handle shifts of between 32 and 63 bits */
MMMORE32:
mov %edx,%eax
sar $31,%edx
and $31,%cl
sar %cl,%eax
ret $12
/* Return double precision 0 or -1, depending on the sign of %edx */
RETSIGN:
sar $31,%edx
mov %edx,%eax
ret $12
GLOBAL_ENTRY_END(x86Sar64Bit)

Просмотреть файл

@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
x86Linux_Support.cpp
*/
#include "NativeCodeCache.h"
#include <string.h>
#include "Fundamentals.h"
#include "MemoryAccess.h"
#include "x86Linux_Support.h"
void* JNIenv = 0;
extern ClassWorld world;
#ifdef DEBUG
// Pointer to the instruction after the call (used by exception handler to check
// I wanted to use:
// void* compileStubReEntryPoint = (void*) ((Uint8*)staticCompileStub + 17);
// but MSDev appears to have a bug, in that compileStubReEntryPoint will be set == (void*)staticCompileStub
// which is clearly wrong.
void* compileStubAddress = (void*)staticCompileStub;
void* compileStubReEntryPoint = (Uint8*)compileStubAddress + 17;
#endif // DEBUG
void *
generateNativeStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry, void *nativeFunction)
{
Method* method = inCacheEntry.descriptor.method;
Uint32 nWords = method->getSignature().nArguments;
assert(method->getModifiers() & CR_METHOD_NATIVE);
extern Uint32 sysInvokeNativeStubs[];
Uint8 stubSize = 10;
void* stub;
// Write out the native stub
stub = inCache.acquireMemory(stubSize);
Uint8* where = (Uint8*)stub;
*where++ = 0x68; // pushl
writeLittleWordUnaligned(where, (uint32)(nativeFunction));
where += 4;
*where++ = 0xe9; // jmp
writeLittleWordUnaligned(where, (Uint8 *) sysInvokeNativeStubs[nWords] - (where + 4));
// Return the address of the stub.
return ((void*)stub);
}
void *
generateJNIGlue(NativeCodeCache& inCache,
const CacheEntry& inCacheEntry,
void *nativeFunction)
{
void* stub;
Method* method = inCacheEntry.descriptor.method;
assert(method->getModifiers() & CR_METHOD_NATIVE);
Uint8 stubSize = 12;
// Write out the JNI compile stub
stub = inCache.acquireMemory(stubSize);
Uint8* where = (Uint8*) stub;
*where++ = 0x58; // popl %eax
*where++ = 0x68; // pushl
writeLittleWordUnaligned(where, (Uint32) JNIenv);
where += 4;
*where++ = 0xe9; // jmp
writeLittleWordUnaligned(where, reinterpret_cast<Uint32>(nativeFunction) - Uint32(where + 4));
return stub;
}
void *
generateCompileStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry)
{
void* stub;
uint8 stubSize = 10;
// Write out the dynamic compile stub
stub = inCache.acquireMemory(stubSize);
Uint8* where = (Uint8*)stub;
*where++ = 0x68; // pushl
writeLittleWordUnaligned(where, (uint32)(&inCacheEntry));
where += 4;
*where++ = 0xe9; // jmp
writeLittleWordUnaligned(where, (Uint8 *) staticCompileStub - (where + 4));
// Return the address of the dynamic stub.
return ((void*)stub);
}
void*
backPatchMethod(void* inMethodAddress, void* inLastPC, void* /*inUserDefined*/)
{
uint32 curAddress = (uint32) inLastPC;
uint32 methodAddress = (uint32) inMethodAddress;
// Compute the relative branch
uint32* relativeBranch = ((uint32*)inLastPC)-1;
int32 offset = methodAddress - curAddress;
// Backpatch the method.
writeLittleWordUnaligned((void*)relativeBranch, offset);
return (inMethodAddress);
}

Просмотреть файл

@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _X86_LINUX_SUPPORT_H_
#define _X86_LINUX_SUPPORT_H_
#include "prtypes.h"
PR_BEGIN_EXTERN_C
extern void staticCompileStub();
PR_END_EXTERN_C
#endif // _X86_LINUX_SUPPORT_H_

Просмотреть файл

@ -0,0 +1,230 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
desantis
holmes a court (commenting)
x86Opcode.cpp
NOTE:
This file is being phased out -- please do not add to it without speaking to simon
*/
#include "CatchAssert.h"
#include "x86Opcode.h"
#include "x86ArgumentList.h"
// Not used anywhere
// { 0x69, 0x00, "imul " } //iaMulImm 69 0000 0000
//================================================================================
/* Opcode Information
Each OpcodeInfo consists of
x86OpcodeInfo {
oiBaseOpcode // generally the opcode, but can have additional info
oiOpcodeInformation // additional info about opcode
oiText // string for fake disassembly
}
Field bits are referred to as [7 6 5 4 3 2 1 0]
--------------------------------------------------------------------------------
ImmediateArithType
eg:
1000 00s1: 11 111 reg:immdata immediate with register
1000 00s1:mod 111 r/m:immdata immediate with memory
oiBaseOpcode
contains the opcode for the instruction
1 (Size) always 0 (assigned at format time)
oiOpcodeInformation
7 set if two byte opcode
6 set if has an opcode extension
[5 4 3] opcode extension of the instructrion
1 set if must take a 1-byte immediate
0 set if must take a 4-byte immediate
others set to 0
*/
x86OpcodeInfo iaInfo[] =
{
// ** *
{ 0x81, 0x40, "add " }, //iaAddImm 81/0 0100 0000
{ 0x81, 0x78, "cmp " }, //iaCmpImm 81/7 0111 1000
{ 0xe9, 0x40, "jmp " }, //iaJmp e9/0 0100 0000
{ 0x68, 0x40, "push "}, //iaPushImm 68/0 0100 0000
{ 0x81, 0x60, "and "}, //iaAndImm 81/4 0110 0000
{ 0x81, 0x48, "or "}, //iaOrImm 81/1 0100 1000
{ 0x81, 0x70, "xor "}, //iaXorImm 81/6 0111 0000
};
/*--------------------------------------------------------------------------------
ExtendedType
eg
1100 0001: 11 111 reg:imm8data reg by immediate count
1100 0001:mod 111 r/m:imm8data memory by immediate count
oiBaseOpcode
contains the opcode for the instruction
oiOpcodeInformation
7 set if two byte opcode
[5 4 3] contain Regfield opcode extension
1 set if can take a 1-byte immediate
0 set if can take a 4-byte immediate
others set to 0
*/
x86OpcodeInfo eInfo[] =
{ // ** *
{ 0xf7, 0x38, "idiv eax, " }, //eIDiv f7/7 0011 1000
{ 0xf7, 0x30, "div eax, " }, //eDiv f7/6 0011 0000
{ 0xf7, 0x20, "div eax, " }, //eMul f7/4 0010 0000
{ 0xc7, 0x01, "movImm " }, //eMoveImm c7/0 0000 0001 // used when won't be condensable
{ 0xff, 0x30, "push "}, //ePush ff/6 0011 0000 // FIX Peter? (what's wrong?)
{ 0xc1, 0x3a, "sar "}, //eSarImm c1/7 0011 1010
{ 0xc1, 0x2a, "shr "}, //eShrImm c1/5 0010 1010
{ 0xc1, 0x22, "shl "}, //eShlImm c1/4 0010 0010
{ 0xd1, 7<<3, "sar(by1) "}, //eSar1 c1/7 0011 1000
{ 0xd1, 5<<3, "shr(by1) "}, //eShr1 c1/5 0010 1000
{ 0xd1, 4<<3, "shl(by1) "}, //eShl1 c1/4 0010 0000
{ 0xd3, 7<<3, "sar(bycl) "}, //eSarCl c1/7 0011 1000
{ 0xd3, 5<<3, "shr(bycl) "}, //eShrCl c1/5 0010 1000
{ 0xd3, 4<<3, "shl(bycl) "}, //eShlCl c1/4 0010 0000
{ 0xf7, 3<<3, "neg "}, //eNeg f7/3 0001 1000
};
/*--------------------------------------------------------------------------------
CondensableExtendedType
Like ExtendedOpcodes but have alternate (condensed) encoding: 5-bit opcode + 3-bit reg operand
eg
0100 0 rg reg (preferred encoding)
1111 1111:mod 000 r/m memory
oiBaseOpcode
contains the opcode for the instruction
oiOpcodeInformation
[7 6 5 4 3] register condensed form opcode
[2 1 0] regfield extension in extended form
NOTE: These opcodes cannot be two bytes and must take 4 BYTE IMMEDIATES
*/
x86OpcodeInfo ceInfo[] =
{ // norm condns <cond><x>
{ 0xff, 0x40, "inc " }, //ceInc ff/0 40+reg 0100 0000
{ 0xff, 0x49, "dec " }, //ceDec ff/1 48+reg 0100 1001
{ 0xc7, 0xb8, "movImm " }, //ceMoveImm c7/0 b8+reg 1011 1000
{ 0xff, 0x46, "pop " } //cePop ff/0 40+reg 0101 0110 // 50+rd, ff/6
};
/*--------------------------------------------------------------------------------
SpecialRegMemType
eg [cmp vrx, 0] is the same as [test vrx, vrx] but the latter saves a byte
eg [mov vrx, 0] = [xor vrx, vrx] but the latter saves 4 bytes
Optimisations like the above can only be applied to reg/reg
oiBaseOpcode
contains the opcode for the instruction
oiOpcodeInformation
7 set if two byte opcode
6 0 means register (StandardType) form
1 means memory (ExtendedType) form
[5 4 3] contain Regfield opcode extension for ExtendedType form
1 set if can take a 1-byte immediate
0 set if can take a 4-byte immediate
Pairing
register form followed by memory form
*/
x86OpcodeInfo srmInfo[] =
{
// cmp vrx, 0 = test vrx, vrx (save 1 byte)
{0x85, 0x00, "test "}, //srmCmpImm0 85/r 0000 0000 (2 bytes)
{0x83, 0x7a, "cmp "}, //srm1NOTUSED 83/7 0111 1010 (2+1 bytes)
// mov vrx, 0 = xor vrx, vrx (save 4 bytes)
{0x31, 0x00, "xor "}, //srmMoveImm0 31/r 0000 0000 (2 bytes)
{0xc7, 0x41, "mov "} //srm3NOTUSED c7/0 0100 0001 (2+4 bytes)
};
//================================================================================
// Member functions
/*--------------------------------------------------------------------------------
x86Opcode_ImmArith -- encodes x86ImmediateArithType
- Sign/size bit which specifies 8 or 32 bits operand
- _possible_ three bit opcode extension (stored in the REG field of the MODR/M byte)
*/
void x86Opcode_ImmArith::
opFormatToMemory(void* inStart, x86ArgumentList& inAL, x86ArgListInstruction& /*inInsn*/ )
{
Uint8* start = (Uint8*) inStart;
if(opInfo->oiOpcodeInformation & kIs_2_Byte_Mask)
*start++ = kPrefix_For_2_Byte;
switch(inAL.alSizeOfImmediate())
{
case(is4ByteImmediate):
*start = opInfo->oiBaseOpcode;
break;
case(is1ByteImmediate):
*start = opInfo->oiBaseOpcode | (0x02);
break;
default:
assert(false); // FIX what other possibilities are there?
break;
}
}
//--------------------------------------------------------------------------------
//x86Opcode_Condensable_Reg -- encodes x86CondensableExtendedType
void x86Opcode_Condensable_Reg::
opFormatToMemory(void* inStart, x86ArgumentList& inAL, x86ArgListInstruction& inInsn)
{
Uint8* start = (Uint8*) inStart;
Uint8 reg = inAL.alGetRegisterOperand(inInsn);
if(reg == NOT_A_REG) // Operand is not a register
*start = opInfo->oiBaseOpcode;
else
*start = (opInfo->oiOpcodeInformation & kCondensed_Op_Mask) | reg; // 5-bit opcode + 3-bit reg
}
bool x86Opcode_Condensable_Reg::
opHasRegFieldExtension(x86ArgumentList& inAL, x86ArgListInstruction& inInsn)
{
Uint8 reg = inAL.alGetRegisterOperand( inInsn );
if(reg == NOT_A_REG) // Operand is not a register
return true;
return false;
}
//--------------------------------------------------------------------------------

Просмотреть файл

@ -0,0 +1,377 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
x86Opcode.h
desantis
simon
NOTE:
This file is being phased out -- please do not add to it without speaking to simon
*/
#ifndef _X86OPCODE
#define _X86OPCODE
#include "CatchAssert.h"
#include <stdio.h>
#include "Fundamentals.h"
#include "LogModule.h"
class x86ArgumentList;
class x86ArgListInstruction;
//================================================================================
// enums
enum x86NoArgsCode
{
opCdq,
opBreak,
opSahf
};
enum x86DoubleOpCode
{
opMul,
opMovSxB,
opMovSxH,
opMovZxB,
opMovZxH
};
enum x86DoubleOpDirCode
{
raAdd,
raAdc,
raSub,
raSbb,
raAnd,
raOr,
raXor,
raCmp,
raLoadI,
raCopyI,
raStoreI,
raSaveReg,
raStoreB,
raStoreH
};
// Floating-point instructions in which one operand is a memory location.
// If there is a second operand, then it is implicitly the top of the FPU stack.
enum x86FloatMemoryType
{
fstp32, // TOS => 32-bit float memory. Pop FPU.
fstp64, // TOS => 64-bit double memory. Pop FPU.
fst32, // TOS => 32-bit float memory. (Don't pop FPU stack.)
fst64, // TOS => 64-bit double memory. (Don't pop FPU stack.)
fistp32, // Round(TOS) => 32-bit int memory. Pop FPU.
fistp64, // Round(TOS) => 64-bit long memory. Pop FPU.
fld32, // 32-bit float memory => Push on FPU stack
fld64, // 64-bit float memory => Push on FPU stack
fild32, // 32-bit int memory => convert to FP and push on FPU stack
fild64, // 64-bit long memory => convert to FP and push on FPU stack
fadd32, // Add TOS and 32-bit float memory => replace TOS
fadd64, // Add TOS and 64-bit double memory => replace TOS
fmul32, // Multiply TOS and 32-bit float memory => replace TOS
fmul64, // Multiply TOS and 64-bit double memory => replace TOS
fsub32, // Subtract TOS from 32-bit float memory => replace TOS
fsub64, // Subtract TOS from 64-bit double memory => replace TOS
fsubr32, // Subtract 32-bit float memory from TOS => replace TOS
fsubr64, // Subtract 64-bit double memory from TOS => replace TOS
fdiv32, // Divide TOS by 32-bit float memory => replace TOS
fdiv64, // Divide TOS by 64-bit double memory => replace TOS
fcomp32, // Compare TOS to 32-bit float memory, setting FPU flags, pop TOS
fcomp64 // Compare TOS to 64-bit double memory, setting FPU flags, pop TOS
};
// enums for the x96 conidtion code
enum x86ConditionCode
{
ccJO = 0x00,
ccJNO = 0x01,
ccJB = 0x02,
ccJNB = 0x03,
ccJE = 0x04,
ccJNE = 0x05,
ccJBE = 0x06,
ccJNBE = 0x07,
ccJS = 0x08,
ccJNS = 0x09,
ccJP = 0x0a,
ccJNP = 0x0b,
ccJL = 0x0c,
ccJNL = 0x0d,
ccJLE = 0x0e,
ccJNLE = 0x0f
};
/*================================================================================
x86 Opcodes
- Can be one byte or two bytes in length. If two bytes, the first byte is 0x0f.
- Can have bits to control:
- data flow direction(D),
- sign extension(S) // FIX pete, isn't this 'size' not 'sign'?
- conditions (cond), and
- register field
- opcode extensions (Reg).
- Can have an alternate (condensed) encoding which allows a single register operand to be encoded in the opcode.
*/
enum x86GPR
{
EAX = 0,
ECX = 1,
EDX = 2,
EBX = 3,
ESP = 4,
EBP = 5,
ESI = 6,
EDI = 7,
NOT_A_REG = 255
};
// bit masks
const int kRegfield_Mask = 0x38; // 0b00111000
const int kIs_Memory_Form_Mask = 0x40; // 0b01000000
const int kCondition_Code_Mask = 0x0f; // 0b00001111
const int kCondensed_Op_Mask = 0xf8; // 0b11111000
const int kIs_2_Byte_Mask = 0x80; // 0b10000000
const int kIs_16_Bit_Mask = 0x40; // 0b01000000
const int kExtension_Mask = 0x40; // 0b01000000
const int kPrefix_For_16_Bits = 0x66;
const int kPrefix_For_2_Byte = 0x0f; // 0b00001111
/*--------------------------------------------------------------------------------
Opcode Information
*/
struct x86OpcodeInfo
{
uint8 oiBaseOpcode; // generally the opcode, but can have additional info
uint8 oiOpcodeInformation; // additional info about opcode
char* oiText; // string for fake disassembly
};
extern x86OpcodeInfo iaInfo[];
enum x86ImmediateArithType
{
iaAddImm,
iaCmpImm,
iaJmp,
iaPushImm,
iaAndImm,
iaOrImm,
iaXorImm
};
extern x86OpcodeInfo eInfo[];
enum x86ExtendedType
{
eIDiv,
eDiv,
eMul,
eMoveImm,
ePush,
eSarImm,
eShrImm,
eShlImm,
eSar1,
eShr1,
eShl1,
eSarCl,
eShrCl,
eShlCl,
eNeg
};
extern x86OpcodeInfo ceInfo[];
enum x86CondensableExtendedType
{
ceInc,
ceDec,
ceMoveImm,
cePop
};
extern x86OpcodeInfo srmInfo[];
enum x86SpecialRegMemType
{
srmCmpImm0,
srm1NOTUSED,
srmMoveImm0,
srm3NOTUSED
};
//================================================================================
// Class Declarations
/*--------------------------------------------------------------------------------
x86Opcode -- encodes x86StandardType
Basic opcode
- 8 or 16 bits
- no toggable bits and
- does NOT have a register field opcode extension or alternate encoding.
*/
class x86Opcode
{
public:
virtual void opPrintPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-9s", opInfo->oiText)); }
virtual uint8 opSize() { return( (opInfo->oiOpcodeInformation >> 7) + 1); }
virtual void opFormatToMemory(void* inStart, x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/);
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ ) { return (false); }
virtual uint8 opGetRegFieldExtension() { assert(false); return 0; }
virtual bool opRegOperandCanBeCondensed() { return false; }
virtual void opReverseOperands() { assert(false); }
virtual void opSwitchToRegisterIndirect() { }
virtual bool opCanAccept1ByteImmediate() { assert(false); return false; }
virtual bool opCanAccept4ByteImmediate() { assert(false); return false; }
protected:
x86Opcode() {}
x86Opcode( x86ImmediateArithType inType ) { opInfo = &(iaInfo[inType]); }
x86Opcode( x86ExtendedType inType ) { opInfo = &(eInfo[inType]); }
x86Opcode( x86CondensableExtendedType inType ) { opInfo = &(ceInfo[inType]); }
x86Opcode( x86SpecialRegMemType inType ) { opInfo = &(srmInfo[inType]); }
x86OpcodeInfo* opInfo;
};
inline void x86Opcode::
opFormatToMemory(void* inStart, x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/)
{
uint8* start = (uint8*) inStart;
if(opInfo->oiOpcodeInformation & kIs_2_Byte_Mask)
*start++ = kPrefix_For_2_Byte;
*start = opInfo->oiBaseOpcode;
}
/*--------------------------------------------------------------------------------
x86Opcode_Reg -- encodes x86EntendedType
- no switchable bits
- three bit opcode extension (stored in the REG field of the MODR/M byte)
*/
class x86Opcode_Reg :
public virtual x86Opcode
{
public:
x86Opcode_Reg ( x86ExtendedType inInfo ) : x86Opcode(inInfo) { }
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ ) { return true; }
virtual uint8 opGetRegFieldExtension() { return (kRegfield_Mask & opInfo->oiOpcodeInformation); }
virtual bool opCanAccept1ByteImmediate() { return ((0x02 & opInfo->oiOpcodeInformation) == 0x02); }
virtual bool opCanAccept4ByteImmediate() { return ((0x01 & opInfo->oiOpcodeInformation) == 0x01); }
protected:
x86Opcode_Reg() { }
};
/*--------------------------------------------------------------------------------
x86Opcode_Condensable_Reg -- encodes x86CondensableExtendedType
- no switchable bits
- three bit opcode extension (stored in the REG field of the MODR/M byte)
- alternate encoding which has a 5-bit opcode + 3-bit register operand
*/
class x86Opcode_Condensable_Reg :
public x86Opcode
{
public:
x86Opcode_Condensable_Reg ( x86CondensableExtendedType inInfo ) : x86Opcode(inInfo) { }
virtual bool opHasRegFieldExtension( x86ArgumentList& inAL, x86ArgListInstruction& inInsn );
virtual uint8 opGetRegFieldExtension() { return ((0x03 & opInfo->oiOpcodeInformation) << 3); }
virtual bool opCanAccept1ByteImmediate() { return false; }
virtual bool opCanAccept4ByteImmediate() { return true; }
virtual bool opRegOperandCanBeCondensed(){ return true; }
virtual uint8 opSize() { return 1; }
virtual void opFormatToMemory(void* inStart, x86ArgumentList& inAL, x86ArgListInstruction& inInsn);
};
/*--------------------------------------------------------------------------------
x86Opcode_ImmArith -- encodes x86ImmediateArithType
- must have sign/size bit which specifies 8 or 32 bits operand
- _possible_ three bit opcode extension (stored in the REG field of the MODR/M byte)
*/
class x86Opcode_ImmArith :
public x86Opcode
{
public:
x86Opcode_ImmArith( x86ImmediateArithType inInfo ) : x86Opcode( inInfo ) { }
virtual void opFormatToMemory( void* inStart, x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/);
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ )
{ return (bool)((opInfo->oiOpcodeInformation >> 6) && 1); }
virtual uint8 opGetRegFieldExtension()
{ assert(kExtension_Mask & opInfo->oiOpcodeInformation); return (kRegfield_Mask & opInfo->oiOpcodeInformation); }
virtual bool opCanAccept1ByteImmediate() { return true; }
virtual bool opCanAccept4ByteImmediate() { return true; }
virtual void opSwitchToRegisterIndirect() { } // FIX can't do this for imul ???
protected:
x86Opcode_ImmArith() { }
};
/*--------------------------------------------------------------------------------
x86Opcode_SpecialRegMem -- x86SpecialRegMemType
- switches between
x86Opcode_Reg when operand is a memory argument, and
x86Opcode when operand is a register argument
*/
class x86Opcode_SpecialRegMem :
public x86Opcode_Reg // note not x86Opcode!
{
public:
x86Opcode_SpecialRegMem( x86SpecialRegMemType inType) :
x86Opcode(inType) { }
virtual bool opHasRegFieldExtension( x86ArgumentList& /*inAL*/, x86ArgListInstruction& /*inInsn*/ )
{
return((kIs_Memory_Form_Mask & opInfo->oiOpcodeInformation) == kIs_Memory_Form_Mask);
}
virtual uint8 opGetRegFieldExtension()
{
assert(kIs_Memory_Form_Mask & opInfo->oiOpcodeInformation);
return (kRegfield_Mask & opInfo->oiOpcodeInformation);
}
virtual void opSwitchToRegisterIndirect()
{
assert(!(kIs_Memory_Form_Mask & opInfo->oiOpcodeInformation));
opInfo++;
}
};
#endif // _X86OPCODE

Просмотреть файл

@ -0,0 +1,250 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86StdCall.cpp - StdCall calling convention
//
#include "x86StdCall.h"
#include "x86Win32Emitter.h"
// Utility function to push one function-call argument on the stack
void
pushCallArg(DataConsumer& argument, DataNode* usesNode, InstructionDefine*& orderingDependency, Pool& inPool, x86Win32Emitter& inEmitter)
{
// Do the first argument specially because that sets up the chain of ordering dependencies
int numOrderingUses = orderingDependency ? 1 : 0;
// If pushing constant arguments, use the immediate form of the push instruction
if (argument.getVariable().getCategory() == pcConst) {
switch (argument.getKind()) {
// 32-bit constants
case vkInt:
case vkAddr:
case vkFloat:
{
Uint32 constant = PrimConst::cast(argument.getVariable()).value.i;
x86Instruction& pushInsn = *new(inPool) x86Instruction(usesNode, inPool, iaPushImm, constant, atImmediateOnly, numOrderingUses, 1);
// First arg is handled differently
if (orderingDependency) {
inEmitter.useTemporaryOrder(pushInsn, *orderingDependency, 0);
inEmitter.redefineTemporaryOrder(pushInsn, *orderingDependency, 0);
} else {
orderingDependency = &inEmitter.defineTemporaryOrder(pushInsn, 0);
}
}
break;
// 64-bit constants require two immediate-form push instructions
case vkDouble:
case vkLong:
{
Int64 constant = PrimConst::cast(argument.getVariable()).value.l;
Int32 low = (Int32)((Uint64)constant & 0xFFFFFFFF);
Int32 high = (Int32)((Uint64)constant >> 32);
x86Instruction& pushInsnHi = *new(inPool) x86Instruction(usesNode, inPool, iaPushImm, high, atImmediateOnly, numOrderingUses, 1);
// First arg is handled differently
if (orderingDependency) {
inEmitter.useTemporaryOrder(pushInsnHi, *orderingDependency, 0);
inEmitter.redefineTemporaryOrder(pushInsnHi, *orderingDependency, 0);
} else {
orderingDependency = &inEmitter.defineTemporaryOrder(pushInsnHi, 0);
}
x86Instruction& pushInsnLo = *new(inPool) x86Instruction(usesNode, inPool, iaPushImm, low, atImmediateOnly, 1, 1);
inEmitter.useTemporaryOrder(pushInsnLo, *orderingDependency, 0);
inEmitter.redefineTemporaryOrder(pushInsnLo, *orderingDependency, 0);
}
break;
default:
assert(0);
}
return;
}
// Push non-constant function call argument
switch (argument.getKind()) {
case vkInt:
case vkAddr:
{
x86Instruction& storeParam = *new(inPool) x86Instruction(usesNode, inPool, ePush, atRegDirect, 1 + numOrderingUses, 1);
inEmitter.useProducer(argument.getVariable(), storeParam, 0);
// First arg is handled differently
if (orderingDependency) {
inEmitter.useTemporaryOrder(storeParam, *orderingDependency, 1);
inEmitter.redefineTemporaryOrder(storeParam, *orderingDependency, 0);
} else {
orderingDependency = &inEmitter.defineTemporaryOrder(storeParam, 0);
}
}
break;
case vkFloat:
{
InsnDoubleOpDir& copyParamInsn = *new(inPool) InsnDoubleOpDir(usesNode, inPool, raCopyI, atRegAllocStackSlot, atRegDirect, 1, 1);
inEmitter.useProducer(argument.getVariable(), copyParamInsn, 0, vrcStackSlot);
VirtualRegister& vr = inEmitter.defineTemporary(copyParamInsn, 0);
x86Instruction& storeParamInsn = *new(inPool) x86Instruction(usesNode, inPool, ePush, atRegDirect, 1 + numOrderingUses, 1);
inEmitter.useTemporaryVR(storeParamInsn, vr, 0);
// First arg is handled differently
if (orderingDependency) {
inEmitter.useTemporaryOrder(storeParamInsn, *orderingDependency, 1);
inEmitter.redefineTemporaryOrder(storeParamInsn, *orderingDependency, 0);
} else {
orderingDependency = &inEmitter.defineTemporaryOrder(storeParamInsn, 0);
}
}
break;
case vkDouble:
{
// Push high 32-bits of double
InsnDoubleOpDir& copyParamInsnHi = *new(inPool) InsnDoubleOpDir(usesNode, inPool, raCopyI, atRegAllocStackSlotHi32, atRegDirect, 1, 2);
inEmitter.useProducer(argument.getVariable(), copyParamInsnHi, 0, vrcStackSlot);
VirtualRegister& vrHi = inEmitter.defineTemporary(copyParamInsnHi, 0);
x86Instruction& storeParamInsnHi = *new(inPool) x86Instruction(usesNode, inPool, ePush, atRegDirect, 1 + numOrderingUses, 1);
inEmitter.useTemporaryVR(storeParamInsnHi, vrHi, 0);
// First arg is handled differently
if (orderingDependency) {
inEmitter.useTemporaryOrder(storeParamInsnHi, *orderingDependency, 1);
inEmitter.redefineTemporaryOrder(storeParamInsnHi, *orderingDependency, 0);
} else {
orderingDependency = &inEmitter.defineTemporaryOrder(storeParamInsnHi, 0);
}
// Push low 32-bits of double
InsnDoubleOpDir& copyParamInsnLo = *new(inPool) InsnDoubleOpDir(usesNode, inPool, raCopyI, atRegAllocStackSlot, atRegDirect, 1, 2);
inEmitter.useProducer(argument.getVariable(), copyParamInsnLo, 0, vrcStackSlot);
VirtualRegister& vrLo = inEmitter.defineTemporary(copyParamInsnLo, 0);
x86Instruction& storeParamInsnLo = *new(inPool) x86Instruction(usesNode, inPool, ePush, atRegDirect, 2, 1);
inEmitter.useTemporaryVR(storeParamInsnLo, vrLo, 0);
inEmitter.useTemporaryOrder(storeParamInsnLo, *orderingDependency, 1);
inEmitter.redefineTemporaryOrder(storeParamInsnLo, *orderingDependency, 0);
}
break;
case vkLong:
{
x86Instruction& storeParamHigh = *new(inPool) x86Instruction(usesNode, inPool, ePush, atRegDirect, 1 + numOrderingUses, 1);
inEmitter.useProducer(argument.getVariable(), storeParamHigh, 0, vrcInteger, vidHigh);
// First arg is handled differently
if (orderingDependency) {
inEmitter.useTemporaryOrder(storeParamHigh, *orderingDependency, 1);
inEmitter.redefineTemporaryOrder(storeParamHigh, *orderingDependency, 0);
} else {
orderingDependency = &inEmitter.defineTemporaryOrder(storeParamHigh, 0);
}
x86Instruction& storeParamLow = *new(inPool) x86Instruction(usesNode, inPool, ePush, atRegDirect, 2, 1);
inEmitter.useProducer(argument.getVariable(), storeParamLow, 0, vrcInteger, vidLow);
inEmitter.useTemporaryOrder(storeParamLow, *orderingDependency, 1);
inEmitter.redefineTemporaryOrder(storeParamLow, *orderingDependency, 0);
}
break;
default:
assert(false);
}
}
void x86Win32Emitter::
emitArguments(ControlNode::BeginExtra& inBeginNode)
{
if (inBeginNode.nArguments == 0)
return;
InsnExternalDefine& defineInsn = *new(mPool) InsnExternalDefine(&inBeginNode[0], mPool, inBeginNode.nArguments * 2);
// do appropriate loads for each argument
Uint32 curStackOffset = 8;
Uint8 curIndex = 0; // Index into defineInsn
unsigned int curArgument;
for (curArgument = 0; curArgument < inBeginNode.nArguments; curArgument++)
{
PrimArg& curArg = inBeginNode[curArgument];
switch (curArg.getOperation())
{
case poArg_I:
case poArg_A:
if (curArg.hasConsumers())
{
InsnDoubleOpDir& loadParam = *new(mPool) InsnDoubleOpDir(&curArg, mPool, raLoadI, curStackOffset, atStackOffset, atRegDirect, 1, 1);
useTemporaryOrder(loadParam, defineTemporaryOrder(defineInsn, curIndex), 0);
defineProducer(curArg, loadParam, 0);
}
curIndex++;
curStackOffset += 4;
break;
case poArg_F:
if (curArg.hasConsumers())
emit_ArgF(curArg, defineTemporaryOrder(defineInsn, curIndex), curStackOffset);
curIndex++;
curStackOffset += 4;
break;
case poArg_L:
if (curArg.hasConsumers())
{
InsnDoubleOpDir& loadHi = *new(mPool) InsnDoubleOpDir(&curArg, mPool, raLoadI, curStackOffset + 4, atStackOffset, atRegDirect, 1, 1);
InsnDoubleOpDir& loadLo = *new(mPool) InsnDoubleOpDir(&curArg, mPool, raLoadI, curStackOffset, atStackOffset, atRegDirect, 1, 1);
useTemporaryOrder(loadLo, defineTemporaryOrder(defineInsn, curIndex), 0);
useTemporaryOrder(loadHi, defineTemporaryOrder(defineInsn, curIndex + 1), 0);
defineProducer(curArg, loadLo, 0, vrcInteger, vidLow);
defineProducer(curArg, loadHi, 0, vrcInteger, vidHigh);
}
curIndex += 2;
curStackOffset += 8;
break;
case poArg_D:
if (curArg.hasConsumers())
emit_ArgD(curArg, defineTemporaryOrder(defineInsn, curIndex), curStackOffset);
curIndex++;
curStackOffset += 8;
break;
default:
assert(false);
}
}
// continue counting from before
// make all the rest of the defines as type none
for (;curIndex < inBeginNode.nArguments * 2; curIndex++)
{
defineInsn.getInstructionDefineBegin()[curIndex].kind = udNone;
}
}

Просмотреть файл

@ -0,0 +1,206 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86StdCall.h - StdCall calling convention
//
#include "x86Win32Instruction.h"
// Utility function to push one function-call argument on the stack
void pushCallArg(DataConsumer &curArgument, DataNode* usesNode, InstructionDefine*& orderingDependency, Pool& inPool, x86Win32Emitter& inEmitter);
// -> mem regarg1 regarg2 regarg3 regarg3
// <- mem [returnval]
// inHasReturnValue is deprecated, and is ignored
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic>
Call<tHasIncomingStore, tHasOutgoingStore, tHasFunctionAddress, tIsDynamic>::
Call( DataNode* inDataNode,
Pool& inPool,
Uint8 inRegisterArguments,
bool /*inHasReturnValue*/,
x86Win32Emitter& inEmitter,
void (*inFunc)(),
DataNode* inUseDataNode) :
InsnUseXDefineYFromPool(inDataNode, inPool, ((inRegisterArguments != 0) ? 1 : 0) + tHasIncomingStore + tIsDynamic, 3)
// add extra use for ordering edge (see below) if more than one argument
{
DataNode* returnValProducer; // node whose outgoing edge is the return value
if (inDataNode->hasKind(vkTuple))
{
// if called with a Primitive with kind vkTuple, we know we will have to deal with a projection edge
const DoublyLinkedList<DataConsumer>& projectionConsumers = inDataNode->getConsumers();
DoublyLinkedList<DataConsumer>::iterator curProjectionEdge = projectionConsumers.begin();
// grab the outgoing store (if there is one)
// set up returnValProducer to point to the return value producer (if it exists)
// one of the two consumers of the projection node must be the memory node, the other must be the Return value node
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();
}
else
{
// non-call Primitive treated as an out-of-line call
assert(!tHasFunctionAddress && !tIsDynamic);
// since outgoing stores are handled separately and are not
// a real return type, we make the return value code ignore
// them
if (tHasOutgoingStore)
{
assert(inDataNode->hasKind(vkMemory));
inEmitter.defineProducer(*inDataNode, *this, 0); //-> mem
returnValProducer = NULL;
}
else
returnValProducer = inDataNode;
}
// pre-color (and buffer) the return value
if (returnValProducer)
{
switch (returnValProducer->getKind())
{
case vkInt:
case vkAddr:
{
VirtualRegister* returnValVR;
// the Call defines a temporary register, which is precolored to
// the appropriate return register
returnValVR = &inEmitter.defineTemporary(*this, 1);
returnValVR->preColorRegister(x86GPRToColor[EAX]);
// now create a "buffer" copy between the precolored return register
// and make the Copy define the return value edge from the poCall
InsnDoubleOpDir& copyInsn = newCopyInstruction(*inDataNode, inPool);
inEmitter.useTemporaryVR(copyInsn, *returnValVR, 0);
inEmitter.defineProducer(*returnValProducer, copyInsn, 0);
// fiX-ME none-out unused return value argument
break;
}
case vkLong:
{
// results returned in eax (low) and edx (high)
VirtualRegister* lowVR;
VirtualRegister* highVR;
lowVR = &inEmitter.defineTemporary(*this, 1);
highVR = &inEmitter.defineTemporary(*this, 2);
lowVR->preColorRegister(x86GPRToColor[EAX]);
highVR->preColorRegister(x86GPRToColor[EDX]);
InsnDoubleOpDir& copyHiInsn = newCopyInstruction(*inDataNode, inPool);
inEmitter.useTemporaryVR(copyHiInsn, *highVR, 0);
inEmitter.defineProducer(*returnValProducer, copyHiInsn, 0, vrcInteger, vidHigh);
InsnDoubleOpDir& copyLowInsn = newCopyInstruction(*inDataNode, inPool);
inEmitter.useTemporaryVR(copyLowInsn, *lowVR, 0);
inEmitter.defineProducer(*returnValProducer, copyLowInsn, 0, vrcInteger, vidLow);
}
break;
case vkFloat:
inEmitter.emit_CallReturnF(*this, *inDataNode, *returnValProducer);
break;
case vkDouble:
inEmitter.emit_CallReturnD(*this, *inDataNode, *returnValProducer);
break;
default:
assert(false);
break;
}
}
else if (!tHasOutgoingStore)
inDataNode->setInstructionRoot(this); // if no outgoing edges (no return value or memory edge, we need to hook this on)
DataConsumer* firstArgument;
DataConsumer* curArgument;
// uses may begin at some passed in node, instead of the node from which the call originates
DataNode* usesNode = (inUseDataNode) ? inUseDataNode : inDataNode;
// incoming store
if (tHasIncomingStore)
inEmitter.useProducer(usesNode->nthInputVariable(0), *this, tIsDynamic + (inRegisterArguments > 0)); // -> mem
firstArgument = usesNode->getInputsBegin() + tHasFunctionAddress + tHasIncomingStore;
// grab the callee address (it might not be a static call)
if (tHasFunctionAddress)
{
assert(inFunc == NULL); // programmer error to specify a function address if this Call has a function address
if (tIsDynamic)
inEmitter.useProducer(usesNode->nthInputVariable(1), *this, 0); // -> incoming address
else
mCalleeAddress = (Uint32) nthInputConstantUint32(*usesNode, 1);
}
else
mCalleeAddress = (Uint32) inFunc;
// start at last argument and push arguments from right to left
curArgument = usesNode->getInputsEnd() - 1; // arguments array is last + 1
// BASIC IDEA:
//
// We are creating a bunch of pushes followed by a call instruction
// Since pushes are clearly ordered operations we need an edge to maintain that ordering.
// We use an order edge defined by the first push, and which is used and by each
// subsequent push. This ends in a use by the Call (*this).
//
// In the end we will have somethinglike Call -> Arg0 -> Arg1 -> ... -> ArgN-1 -> ArgN
// where Call is the call instruction and the Arg's are pushes.
//
// The scheduler will walk up the use chain and do the last arg first and then come
// back down the chain.
InstructionDefine* orderingDependency = NULL; // maintains "thread" to order the pushes of the arguments
if(curArgument >= firstArgument)
{
// Generate pushes for the arguments. Order them with Order Edges.
// Note x86 arguments are pushed on the stack from right to left.
for (; curArgument >= firstArgument; curArgument--)
pushCallArg(*curArgument, usesNode, orderingDependency, inPool, inEmitter);
// this is the final order edge which is attached to the Call instruction
inEmitter.useTemporaryOrder(*this, *orderingDependency, tIsDynamic);
}
}

Просмотреть файл

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#if !defined(_X86WIN32_CPU_H_) || defined(INCLUDE_EMITTER)
#define _X86WIN32_CPU_H_
#define FIRST_CALLEE_SAVED_GR 4
#define LAST_CALLEE_SAVED_GR 6
#define FIRST_CALLER_SAVED_GR 0
#define LAST_CALLER_SAVED_GR 3
#define FIRST_CALLEE_SAVED_FPR 0
#define LAST_CALLEE_SAVED_FPR -1
#define FIRST_CALLER_SAVED_FPR 0
#define LAST_CALLER_SAVED_FPR -1
#define FIRST_GREGISTER 0
#define LAST_GREGISTER 5
#define FIRST_FPREGISTER 0
#define LAST_FPREGISTER -1
#define NUMBER_OF_SPECIAL_REGISTERS 0
class x86Win32Emitter;
class x86Formatter;
typedef x86Formatter MdFormatter;
typedef x86Win32Emitter MdEmitter;
#ifdef INCLUDE_EMITTER
#include "x86Win32Emitter.h"
#include "x86Formatter.h"
#endif
#define CPU_IS_SUPPORTED
#endif /* _X86WIN32_CPU_H_ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,333 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86Win32Emitter.h
//
// Peter DeSantis
// Simon Holmes a Court
//
#ifndef X86_WIN32_EMITTER
#define X86_WIN32_EMITTER
#include "InstructionEmitter.h"
#include "VirtualRegister.h"
#include "ControlNodes.h"
#include "x86Opcode.h"
class x86Instruction;
class InsnFloatMemory;
class x86ArgListInstruction;
class InsnDoubleOpDir;
//-----------------------------------------------------------------------------------------------------------
inline Uint32 nthInputConstantUint32(/* const */ DataNode& inPrimitive, size_t inWhich)
{
PrimConst* primConst = static_cast<PrimConst*>(&inPrimitive.nthInputVariable(inWhich));
assert(primConst->hasCategory(pcConst));
Uint32 constant;
bool test = extractU32(primConst->value, constant);
assert(test);
return constant;
}
//-----------------------------------------------------------------------------------------------------------
// MemDSIParameters
// common operations performed by all MemDSI modes
class MemDSIParameters
{
public:
DataNode& addImmPrimitive;
DataNode& addPrimitive;
DataNode& shiftPrimitive;
DataNode& baseProducer;
DataNode& indexProducer;
uint32 displacement;
uint32 scale;
MemDSIParameters(DataNode& inNode) : // should be load or store
addImmPrimitive(inNode.nthInputVariable(1)),
addPrimitive(addImmPrimitive.nthInputVariable(0)),
shiftPrimitive(addPrimitive.nthInputVariable(1)),
baseProducer(addPrimitive.nthInputVariable(0)),
indexProducer(shiftPrimitive.nthInputVariable(0))
{
displacement = nthInputConstantUint32(addImmPrimitive, 1);
scale = nthInputConstantUint32(shiftPrimitive, 1);
}
};
//-----------------------------------------------------------------------------------------------------------
enum x86AddressModeType
{
amNormal,
amMemDisp,
amMemDSI
};
enum RawConditionCode
{
rawLt,
rawEq,
rawLe,
rawGt,
rawLgt,
rawGe
};
//-----------------------------------------------------------------------------------------------------------
// x86Win32Emitter
class x86Win32Emitter :
public InstructionEmitter
{
friend class x86Instruction;
friend class x86Formatter;
public:
x86Win32Emitter(Pool& inPool, VirtualRegisterManager& vrMan) :
InstructionEmitter(inPool, vrMan)
{ }
void emitPrimitive(Primitive& inPrimitive, NamedRule inRule);
VirtualRegister& emit_CopyOfInput(x86ArgListInstruction& inInsn, DataNode& inPrimitive, Uint8 inWhichInput, VirtualRegisterID inID = vidLow);
void emitArguments(ControlNode::BeginExtra& inBeginNode);
bool emitCopyAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& fromVr, VirtualRegister& toVr);
void emitLoadAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& loadedReg, VirtualRegister& stackReg);
void emitStoreAfter(DataNode& inDataNode, InstructionList::iterator where, VirtualRegister& storedReg, VirtualRegister& stackReg);
virtual Instruction& emitAbsoluteBranch(DataNode& inDataNode, ControlNode& inTarget);
void emit_CallReturnF(InsnUseXDefineYFromPool& callInsn, DataNode& callPrimitive, DataNode& returnValProducer);
void emit_CallReturnD(InsnUseXDefineYFromPool& callInsn, DataNode& callPrimitive, DataNode& returnValProducer);
void emit_ArgF(PrimArg& arg, InstructionDefine& order, int curStackOffset);
void emit_ArgD(PrimArg& arg, InstructionDefine& order, int curStackOffset);
private:
void emit_LoadAddress(Primitive& inPrimitive);
// break
void emit_Break(Primitive& inPrimitive);
// result
void emit_Result_I(Primitive& inPrimitive);
void emit_Result_L(Primitive& inPrimitive);
void emit_Result_F(Primitive& inPrimitive);
void emit_Result_D(Primitive& inPrimitive);
void emit_Ld_I_MemDisp(Primitive& inPrimitive);
void emit_LimitR(Primitive& inPrimitive);
void emit_Limit(Primitive& inPrimitive);
void emit_ExceptionCheck(Primitive& inPrimitive, x86ConditionCode condType, Uint32 constant,
void (*throwExceptionFunction)());
void emit_LimCast(Primitive& inPrimitive);
void emit_ChkCast(Primitive& inPrimitive);
void emit_ChkCast_Const(Primitive& inPrimitive);
void emit_ChkNull(Primitive& inPrimitive);
void emit_LoadConstant_I(Primitive& inPrimitive);
void emit_LoadConstant_L(Primitive& inPrimitive);
void emit_LoadConstant_F(Primitive& inPrimitive);
void emit_LoadConstant_D(Primitive& inPrimitive);
void genLdC_I(Primitive& inPrimitive);
void genLd_I(Primitive& inPrimitive);
void emit_Ld_L(Primitive& inPrimitive);
void emit_St_L(Primitive& inPrimitive);
// condition consumers
void emit_B(Primitive& inPrimitive, RawConditionCode rawCondType);
void emit_Cond(Primitive& inPrimitive, RawConditionCode rawCondType);
// logical operator helpers
void genLogicI_I(Primitive& inPrimitive, x86ImmediateArithType iaType);
void genLogic_I(Primitive& inPrimitive, x86DoubleOpDirCode raType);
void emit_Logic_L(Primitive& inPrimitive, x86DoubleOpDirCode insnType);
// and
void emit_AndI_I(Primitive& inPrimitive);
void emit_And_I(Primitive& inPrimitive);
void emit_And_L(Primitive& inPrimitive);
// or
void emit_OrI_I(Primitive& inPrimitive);
void emit_Or_I(Primitive& inPrimitive);
void emit_Or_L(Primitive& inPrimitive);
// xor
void emit_XorI_I(Primitive& inPrimitive);
void emit_Xor_I(Primitive& inPrimitive);
void emit_Xor_L(Primitive& inPrimitive);
// shift helpers
void genShiftI_I(Primitive& inPrimitive, x86ExtendedType eByImmediate, x86ExtendedType eBy1);
void genShift_I(Primitive& inPrimitive, x86ExtendedType eByCl);
// shl
void emit_ShlI_I(Primitive& inPrimitive);
void emit_Shl_I(Primitive& inPrimitive);
void emit_Shl_L(Primitive& inPrimitive);
// sar
void emit_SarI_I(Primitive& inPrimitive);
void emit_Sar_I(Primitive& inPrimitive);
void emit_Sar_L(Primitive& inPrimitive);
// shr
void emit_ShrI_I(Primitive& inPrimitive);
void emit_Shr_I(Primitive& inPrimitive);
void emit_Shr_L(Primitive& inPrimitive);
// mul
void emit_Mul_I(Primitive& inPrimitive);
// void emit_MulI_I(Primitive& inPrimitive); // not yet implemented
void emit_Mul_L(Primitive& inPrimitive);
void emit_Add_I(Primitive& inPrimitive);
void emit_AddI_I(Primitive& inPrimitive);
void emit_Add_L(Primitive& inPrimitive);
void emit_Arithmetic_L(Primitive& inPrimitive, x86DoubleOpDirCode insnTypeLo,
x86DoubleOpDirCode insnTypeHi);
void emit_Sub_I(Primitive& inPrimitive);
void emit_Sub_L(Primitive& inPrimitive);
void emit_SubR_I(Primitive& inPrimitive);
void emit_Cmp_I(Primitive& inPrimitive);
void emit_CmpI_I(Primitive& inPrimitive);
void emit_3wayCmpL_L(Primitive& inPrimitive);
void emit_3wayCmpCL_L(Primitive& inPrimitive);
void emit_3wayCmpF_L(Primitive& inPrimitive);
void emit_3wayCmpF_G(Primitive& inPrimitive);
void emit_3wayCmpD_L(Primitive& inPrimitive);
void emit_3wayCmpD_G(Primitive& inPrimitive);
void emit_3wayCmpCF_L(Primitive& inPrimitive);
void emit_3wayCmpCF_G(Primitive& inPrimitive);
void emit_3wayCmpCD_L(Primitive& inPrimitive);
void emit_3wayCmpCD_G(Primitive& inPrimitive);
void emit_Limit_MemDisp(Primitive& inPrimitive);
void emit_LimitR_MemDisp(Primitive& inPrimitive);
void emit_CmpI_I_MemDSI(Primitive& inPrimitive);
void emit_Cmp_I_MemDSI(Primitive& inPrimitive);
// div/mod
void emit_Div_L(Primitive& inPrimitive);
void emit_Mod_L(Primitive& inPrimitive);
void emit_Div_I(Primitive& inPrimitive);
void emit_DivU_I(Primitive& inPrimitive);
void emit_Mod_I(Primitive& inPrimitive);
void emit_ModU_I(Primitive& inPrimitive);
void emit_Div_I_MemDSI(Primitive& inPrimitive);
void emit_DivU_I_MemDSI(Primitive& inPrimitive);
void emit_Mod_I_MemDSI(Primitive& inPrimitive);
void emit_ModU_I_MemDSI(Primitive& inPrimitive);
// div/mod helpers
x86Instruction& genDivMod_FrontEnd(Primitive& inPrimitive, x86ExtendedType insnType);
x86Instruction& genDivMod_FrontEnd_MemDSI(Primitive& inPrimitive, x86ExtendedType insnType);
x86Instruction& genDivMod_FrontEnd_CInt(Primitive& inPrimitive, x86ExtendedType insnType);
void genDivBackEnd(x86Instruction& inInsn);
void genModBackEnd(x86Instruction& inInsn);
// extract
void emit_Ext_I(Primitive& inPrimitive);
void emit_Ext_L(Primitive& inPrimitive);
// Floating Point Utilities
void emit_BinaryFloat(Primitive& inPrimitive,
x86FloatMemoryType binary_op, x86FloatMemoryType load_op, x86FloatMemoryType store_op,
VRClass vrClass);
void emit_BinaryFloat32(Primitive& inPrimitive,
x86FloatMemoryType binary_op);
void emit_BinaryFloat64(Primitive& inPrimitive,
x86FloatMemoryType binary_op);
void emit_3wayCmpF(Primitive& inPrimitive, DataNode& first_operand, DataNode& second_operand,
bool negate_result, x86FloatMemoryType load_op, x86FloatMemoryType cmpOp, VRClass vrClass);
InsnDoubleOpDir& copyFromFloatToIntegerRegister(DataNode& inDataNode, InsnUseXDefineYFromPool& defInsn);
InsnDoubleOpDir& copyFromIntegerRegisterToFloat(DataNode& inDataNode, InsnUseXDefineYFromPool& defInsn);
// Floating Point
void emit_FAdd_F(Primitive& inPrimitive);
void emit_FAdd_D(Primitive& inPrimitive);
void emit_FMul_F(Primitive& inPrimitive);
void emit_FMul_D(Primitive& inPrimitive);
void emit_FSub_F(Primitive& inPrimitive);
void emit_FSub_D(Primitive& inPrimitive);
void emit_FDiv_F(Primitive& inPrimitive);
void emit_FDiv_D(Primitive& inPrimitive);
void emit_FRem_F(Primitive& inPrimitive);
void emit_FRem_D(Primitive& inPrimitive);
// convert
void emit_ConvI_L(Primitive& inPrimitive);
void emit_ConvL_I(Primitive& inPrimitive);
void emit_FConv(Primitive& inPrimitive);
// load
void emit_Ld_I_MemDSI(Primitive& inPrimitive);
void emit_LdS_B(Primitive& inPrimitive);
void emit_LdU_B(Primitive& inPrimitive);
void emit_LdS_H(Primitive& inPrimitive);
void emit_LdU_H(Primitive& inPrimitive);
void emit_Ld_F(Primitive& inPrimitive);
void emit_Ld_D(Primitive& inPrimitive);
// store
void emit_St_B(Primitive& inPrimitive);
void emit_St_H(Primitive& inPrimitive);
void emit_StI_I(Primitive& inPrimitive);
void emit_St_I(Primitive& inPrimitive);
void emit_St_I_MemDSI(Primitive& inPrimitive);
void emit_StI_I_MemDisp(Primitive& inPrimitive);
void emit_St_I_MemDisp(Primitive& inPrimitive);
void emit_St_F(Primitive& inPrimitive);
void emit_St_D(Primitive& inPrimitive);
// catch
void emit_Catch(Primitive& inPrimitive);
// switch
void emit_Switch(Primitive& inPrimitive);
// monitors
void emit_MonitorEnter(Primitive& inPrimitive);
void emit_MonitorExit(Primitive& inPrimitive);
};
#endif // X86_WIN32_EMITTER

Просмотреть файл

@ -0,0 +1,695 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86Win32Instruction.cpp
//
// Simon Holmes a Court
// Peter DeSantis
#include "prtypes.h"
#include "x86Win32Instruction.h"
#include "InstructionEmitter.h"
#include "x86Formatter.h"
class x86Win32Emitter;
extern char* x86GPRText[];
UT_DEFINE_LOG_MODULE(x86Spill);
//================================================================================
// Debugging Structures
#ifdef DEBUG_LOG
char* conditionalSuffixes[] =
{
"o", // ccJO
"no", // ccJNO
"b", // ccJB
"nb", // ccJNB
"e", // ccJE
"ne", // ccJNE
"be", // ccJBE
"nbe", // ccJNBE
"s", // ccJS
"ns", // ccJNS
"p", // ccJP
"np", // ccJNP
"l", // ccJL
"nl", // ccJNL
"le", // ccJLE
"nle", // ccJNLE
};
#endif // DEBUG_LOG
//================================================================================
// x86ArgListInstruction Methods
// For now this is a member of x86ArgListInstruction, but it really should be available for all
// instructions on the x86 platform
// Method: x86StandardUseDefine
// Caller: Emitter
// Purpose: Due to x86 behaviour of modifying source register, we must make a copy of the source before
// the operation. Unnecessary copies can be removed by the register allocator.
void x86ArgListInstruction::
x86StandardUseDefine(x86Win32Emitter& inEmitter)
{
InstructionUse* instructionUseBegin = getInstructionUseBegin();
InstructionDefine* instructionDefineBegin = getInstructionDefineBegin();
Uint8 curIndex;
// Copy the virtual register which will be overwritten
VirtualRegister& vrToBeOverwritten = inEmitter.emit_CopyOfInput(*this, *mSrcPrimitive, 0);
inEmitter.useProducer(*mSrcPrimitive, *this, 0);
// Set the rest of the uses.
InstructionUse* curUse;
for (curUse = instructionUseBegin + 1, curIndex = 1; curUse < getInstructionUseEnd(); curUse++, curIndex++)
addStandardUse(inEmitter, curIndex);
// Now redefine the copied register.
inEmitter.redefineTemporary(*this, vrToBeOverwritten, 0);
assert(instructionDefineBegin + 1 >= getInstructionDefineEnd());
//// Set the rest of the defines.
//InstructionDefine* curDefine;
//for (curDefine = instructionDefineBegin + 1, curIndex = 1; curDefine < getInstructionDefineEnd(); curDefine++, curIndex++)
// inEmitter.defineProducer(nthOutputProducer(*mSrcPrimitive, curIndex), *this, curIndex);
}
// Method: switchUseToSpill
// Caller: Register Allocator
// Purpose: Folds the spill into the instruction if possible.
// Returns: Returns true if possible, false otherwise
bool x86ArgListInstruction::
switchUseToSpill(Uint8 inWhichUse, VirtualRegister& inVR)
{
#ifdef DEBUG_LOG
UT_LOG(x86Spill, PR_LOG_DEBUG, (" spill use %d of (%p)'", inWhichUse, this));
printOpcode(UT_LOG_MODULE(x86Spill));
#endif
DEBUG_ONLY(checkIntegrity();)
if (!opcodeAcceptsSpill())
goto SpillFail;
// Ask the argument list if it can switch the current argument
if (iArgumentList->alSwitchArgumentTypeToSpill(inWhichUse, *this)) // has side effect!
{
// Tell the Opcode that the argumentlist has been switched to a spill
switchOpcodeToSpill();
// Replace the old virtual register with a new one which contains the colored stack slot.
InstructionUse& use = getInstructionUseBegin()[inWhichUse];
InstructionDefine& define = getInstructionDefineBegin()[0];
assert(use.isVirtualRegister());
if(inWhichUse == 0 && define.isVirtualRegister() && use.getVirtualRegister().getRegisterIndex() == define.getVirtualRegister().getRegisterIndex())
// this virtual register is also redefined by this instruction so we must reinitialize the define also
define.getVirtualRegisterPtr().initialize(inVR);
use.getVirtualRegisterPtr().initialize(inVR);
DEBUG_ONLY(checkIntegrity();)
goto SpillSuccess;
}
// by default we fail
SpillFail:
UT_LOG(x86Spill, PR_LOG_DEBUG, ("': false\n"));
DEBUG_ONLY(checkIntegrity();)
return false;
SpillSuccess:
UT_LOG(x86Spill, PR_LOG_DEBUG, ("': true\n"));
DEBUG_ONLY(checkIntegrity();)
return true;
}
// Method: switchDefineToSpill
// Caller: Register Allocator
// Purpose: Folds the spill into the instruction if possible.
// Returns: Returns true if possible, false otherwise
bool x86ArgListInstruction::
switchDefineToSpill(Uint8 inWhichDefine, VirtualRegister& inVR)
{
#ifdef DEBUG_LOG
UT_LOG(x86Spill, PR_LOG_DEBUG, (" spill def %d of (%p)'", inWhichDefine, this));
printOpcode(UT_LOG_MODULE(x86Spill));
#endif
DEBUG_ONLY(checkIntegrity();)
assert(inWhichDefine == 0); // can only switch the first define
InstructionUse& use = getInstructionUseBegin()[0];
InstructionUse* useEnd = getInstructionUseEnd();
InstructionDefine& define = getInstructionDefineBegin()[inWhichDefine];
assert(define.isVirtualRegister()); // cannot call this routine on anything other than a virtual register
// some instructions cannot spill
if (!opcodeAcceptsSpill())
goto SpillFail;
// If this register is being redefined then it should correspond to the first use
// Make sure that there is a first use
if(&use < useEnd)
{
// If it is indeed the same virtual register
if(use.isVirtualRegister() && use.getVirtualRegister().getRegisterIndex() == define.getVirtualRegister().getRegisterIndex())
{
// define == first use, try to switch the first argument to spill type
if(opcodeAcceptsSpill() && iArgumentList->alSwitchArgumentTypeToSpill(0, *this))
{
switchOpcodeToSpill(); // Tell the Opcode that the argumentlist has been switched to a spill
// Replace the old virtual register with a new one which contains the colored stack slot
// The define is also the same as the use so we need to reinitialize both the use and the define VR.
use.getVirtualRegisterPtr().initialize(inVR);
define.getVirtualRegisterPtr().initialize(inVR);
goto SpillSuccess;
}
}
else
{
// There are no other VRs in the uses, define is the second argument
if(opcodeAcceptsSpill() && iArgumentList->alSwitchArgumentTypeToSpill(1, *this))
{
switchOpcodeToSpill(); // Tell the Opcode that the argumentlist has been switched to a spill
// Replace the old virtual register with a new one which contains the colored stack slot
define.getVirtualRegisterPtr().initialize(inVR);
goto SpillSuccess;
}
}
}
else
{
// There are no VRs in the uses so we need to try to switch the first argument
if(opcodeAcceptsSpill() && iArgumentList->alSwitchArgumentTypeToSpill(0, *this))
{
switchOpcodeToSpill(); // Tell the Opcode that the argumentlist has been switched to a spill
// Replace the old virtual register with a new one which contains the colored stack slot
define.getVirtualRegisterPtr().initialize(inVR);
goto SpillSuccess;
}
}
// by default we fail
SpillFail:
UT_LOG(x86Spill, PR_LOG_DEBUG, ("': false\n"));
DEBUG_ONLY(checkIntegrity();)
return false;
SpillSuccess:
UT_LOG(x86Spill, PR_LOG_DEBUG, ("': true\n"));
DEBUG_ONLY(checkIntegrity();)
return true;
}
//================================================================================
// x86Instruction
void x86Instruction::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter)
{
assert(iOpcode != NULL && iArgumentList != NULL);
// Format the opcode to memory
iOpcode->opFormatToMemory(inStart, *iArgumentList, *this);
// Find the location of the argumnet list and format it to memory
Uint8* argLocation = (Uint8*)inStart + iOpcode->opSize();
iArgumentList->alFormatToMemory((void*)argLocation , inOffset, *this, inFormatter);
// If the opcode has an opcode extension then or it into the proper place. ( the reg field of the modr/m byte.)
if(iOpcode->opHasRegFieldExtension( *iArgumentList, *this ))
{
Uint8 temp = iOpcode->opGetRegFieldExtension();
*argLocation = *argLocation | temp;
}
}
//================================================================================
// InsnSwitch
InsnSwitch::
InsnSwitch(DataNode* inPrimitive, Pool& inPool) :
InsnUseXDefineYFromPool(inPrimitive, inPool, 1, 0 )
{
mControlNode = inPrimitive->getContainer();
assert(mControlNode);
mNumCases = mControlNode->nSuccessors();
}
void InsnSwitch::
formatToMemory(void* inStartAddress, Uint32 /*inOffset*/, MdFormatter& inFormatter)
{
Uint8* start = (Uint8*)inStartAddress;
// calculate position of jump table
mTableAddress = start + 7;
// get the register
Uint8 reg = useToRegisterNumber(*getInstructionUseBegin());
assert (reg != ESP); // ESP is an invalid index
// calculate the SIB
Uint8 SIB = 0x80 | ( reg << 3) | 0x05;
// write out instruction
*start++ = 0xff; // opcode for jump
*start++ = 0x24; // mod/ext/rm for jmp disp32[reg * 4]
*start++ = SIB;
// write address of jump table
writeLittleWordUnaligned(start, (int)mTableAddress);
// write out table
Uint8* methodBegin = inFormatter.getMethodBegin();
ControlEdge* edgesEnd = mControlNode->getSuccessorsEnd();
for(ControlEdge* edge = mControlNode->getSwitchSuccessors(); edge != edgesEnd; edge++)
{
Uint8* destAddress = methodBegin + edge->getTarget().getNativeOffset();
start += 4;
writeLittleWordUnaligned(start, (Uint32)destAddress);
}
}
size_t InsnSwitch::
getFormattedSize(MdFormatter& /*inFormatter*/)
{
// reserve 7 bytes for the indexed jump, plus 4 bytes per entry
return 7 + (4 * mNumCases);
}
#ifdef DEBUG_LOG
void InsnSwitch::
printPretty(LogModuleObject &f)
{
Uint8 reg = useToRegisterNumber(*getInstructionUseBegin());
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("jmp 0x%x[4 * %s]", Uint32(mTableAddress), x86GPRText[reg]));
// print table
ControlEdge* edgesEnd = mControlNode->getSuccessorsEnd();
for(ControlEdge* edge = mControlNode->getSwitchSuccessors(); edge != edgesEnd; edge++)
{
Uint32 destAddress = edge->getTarget().getNativeOffset();
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n Method Start + 0x%x [<A HREF=\"#N%d\">N%d</A>]",
destAddress, edge->getTarget().dfsNum, edge->getTarget().dfsNum));
}
}
#endif
//================================================================================
// InsnCondBranch
void InsnCondBranch::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/)
{
uint8* start = (uint8*) inStart;
*start++ = 0x0f;
*start++ = 0x80 | condType;
// find destination
ControlNode& cnoTarget = cnoSource.getTrueSuccessor().getTarget();
// To compute the relative branch we subtract our current address from out target address. Then we subtract the size
// of our instruction because our current IP is actually there. This is the sum of the size of the opcode and the size of the
// argumentlist. NOTE: If we use 1 byte jumps in the future then this needs to be fixed from a constant 4.
const int opcodeSize = 2;
Int32 jumpOffset = cnoTarget.getNativeOffset() - inOffset - opcodeSize - 4;
writeLittleWordUnaligned(start, jumpOffset);
}
#ifdef DEBUG_LOG
void InsnCondBranch::
printPretty(LogModuleObject &f)
{
ControlNode& cnoTarget = cnoSource.getTrueSuccessor().getTarget();
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("j%-7s start+%0d [<A HREF=\"#N%d\">N%d</A>]",
conditionalSuffixes[condType], cnoTarget.getNativeOffset(), cnoTarget.dfsNum, cnoTarget.dfsNum));
}
#endif
//================================================================================
// Set
// Can only be EAX, ECX, EDX or EBX
void InsnSet::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/ )
{
uint8* start = (uint8*) inStart;
// format the opcode to memory
*start++ = 0x0f;
*start++ = 0x90 | condType;
// find the register
InstructionDefine* defineBegin = getInstructionDefineBegin();
#ifdef DEBUG
InstructionUse* useBegin = getInstructionUseBegin();
InstructionUse* useEnd = getInstructionUseEnd();
assert(useBegin < useEnd); // condition code always used
InstructionDefine* defineEnd = getInstructionDefineEnd();
assert((defineBegin < defineEnd) && defineBegin->isVirtualRegister());
#endif
Uint8 reg = defineToRegisterNumber(*defineBegin);
assert(/* (reg >= 0) && */ (reg <= 3)); // these are the only legal registers
// format the register
Uint8 modRM = 0xc0 | reg;
*start = modRM;
}
#ifdef DEBUG_LOG
void InsnSet::
printPretty(LogModuleObject &f)
{
InstructionDefine* defineBegin = getInstructionDefineBegin();
Uint8 reg = defineToRegisterNumber(*defineBegin);
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("set%-5s %s", conditionalSuffixes[condType], x86GPRText[reg]));
}
#endif
//================================================================================
// InsnCondSysCallBranch
#ifdef DEBUG_LOG
void InsnSysCallCondBranch::
printPretty(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("j%-7s (over next)\n call %p", conditionalSuffixes[condType], functionAddress));
}
#endif
//================================================================================
// InsnCondSysCallBranch
struct x86NoArgsInfo
{
uint8 opcode; // generally the opcode, but can have additional info
// eventually will be in DEBUG_LOG build only
char* text; // string for fake disassembly
};
x86NoArgsInfo noArgsInfo[] =
{
{ 0x99, "cdq" }, //opCdq 99
{ 0xcc, "int 3" }, //opBreak cc
{ 0x9e, "sahf" }, //opSahf 9e
};
void InsnNoArgs::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
*((Uint8*)inStart) = (Uint8) noArgsInfo[code].opcode;
}
#ifdef DEBUG_LOG
void InsnNoArgs::
printPretty(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-8s", noArgsInfo[code].text));
}
#endif
//================================================================================
// InsnDoubleOp Methods
struct x86DoubleOpInfo
{
uint8 opcode; // generally the opcode, but can have additional info
bool hasPrefix; // does the opcode needs to be prefixed with 0x0f
// eventually will be in DEBUG_LOG build only
char* text; // string for fake disassembly
};
x86DoubleOpInfo doubleOpInfo[] =
{
{ 0xaf, true, "imul " }, //opIMul 0f af
{ 0xbe, true, "movsxB "}, //opMovSxB 0f be
{ 0xbf, true, "movsxH "}, //opMovSxH 0f bf
{ 0xb6, true, "movzxB "}, //opMovZxB 0f b6
{ 0xb7, true, "movzxH "} //opMovZxH 0f b7
};
InsnDoubleOp::
InsnDoubleOp( DataNode* inPrimitive, Pool& inPool, x86DoubleOpCode inCodeType,
x86ArgumentType inArgType1, x86ArgumentType inArgType2,
Uint8 uses, Uint8 defines ) :
x86ArgListInstruction (inPrimitive, inPool, uses, defines ),
codeType(inCodeType)
{
iArgumentList = new x86DoubleArgumentList(inArgType1, inArgType2);
DEBUG_ONLY(debugType = kInsnDoubleOp);
}
InsnDoubleOp::
InsnDoubleOp( DataNode* inPrimitive, Pool& inPool, x86DoubleOpCode inCodeType,
Uint32 inDisplacement,
x86ArgumentType inArgType1, x86ArgumentType inArgType2,
Uint8 uses, Uint8 defines) :
x86ArgListInstruction (inPrimitive, inPool, uses, defines ),
codeType(inCodeType)
{
iArgumentList = new x86DoubleArgumentList(inArgType1, inArgType2, inDisplacement);
DEBUG_ONLY(debugType = kInsnDoubleOp);
}
void InsnDoubleOp::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter)
{
uint8* start = (uint8*) inStart;
assert(iArgumentList);
// Format the opcode to memory
if(doubleOpInfo[codeType].hasPrefix)
*start++ = kPrefix_For_2_Byte;
*start = doubleOpInfo[codeType].opcode;
// Find the location of the argumnet list and format it to memory
Uint8* argLocation = (Uint8*)inStart + opcodeSize();
iArgumentList->alFormatToMemory((void*)argLocation , inOffset, *this, inFormatter);
}
Uint8 InsnDoubleOp::
opcodeSize()
{
return (doubleOpInfo[codeType].hasPrefix) ? 2 : 1;
}
#ifdef DEBUG_LOG
void InsnDoubleOp::
printOpcode(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-8s ", doubleOpInfo[codeType].text));
}
#endif
//================================================================================
// InsnDoubleOpDir Methods
// used for debugging only (for now)
enum raType
{
kArith,
kLoad,
kStore,
kCopy
};
struct x86RAOpcodeInfo
{
uint8 opcode; // generally the opcode, but can have additional info
bool needs16BitPrefix; // does the opcode need the 'force to 16 bit' opcode?
raType type; // is it a move
// eventually will be in DEBUG_LOG build only
char* text; // string for fake disassembly
};
// note: store dest, source
// note: copy
x86RAOpcodeInfo raInfo[] =
{
{ 0x01, false, kArith, "add " }, //raAdd
{ 0x11, false, kArith, "adc " }, //raAdc
{ 0x29, false, kArith, "sub " }, //raSub
{ 0x19, false, kArith, "sbb " }, //raSbb
{ 0x21, false, kArith, "and " }, //raAnd
{ 0x09, false, kArith, "or " }, //raOr
{ 0x31, false, kArith, "xor " }, //raXor
{ 0x39, false, kArith, "cmp " }, //raCmp
{ 0x89, false, kLoad, "mov(ld) " }, //raLoadI
{ 0x89, false, kCopy, "mov(cp) " }, //raCopyI
{ 0x89, false, kStore, "mov(st) " }, //raStoreI
{ 0x89, false, kStore, "mov(sv) " }, //raSaveReg
{ 0x88, false, kStore, "movB "}, //raStoreB
{ 0x89, true, kStore, "movH "}, //raStoreH
};
InsnDoubleOpDir::
InsnDoubleOpDir(DataNode* inPrimitive, Pool& inPool, x86DoubleOpDirCode inCodeType,
x86ArgumentType inArgType1, x86ArgumentType inArgType2,
Uint8 uses, Uint8 defines ) :
x86ArgListInstruction (inPrimitive, inPool, uses, defines ),
codeType(inCodeType)
{
iArgumentList = new x86DoubleArgumentList(inArgType1, inArgType2);
DEBUG_ONLY(debugType = kInsnDoubleOpDir);
// temp for asserts
getDirectionBit();
}
InsnDoubleOpDir::
InsnDoubleOpDir(DataNode* inPrimitive, Pool& inPool, x86DoubleOpDirCode inCodeType,
Uint32 inDisplacement, x86ArgumentType inArgType1, x86ArgumentType inArgType2,
Uint8 uses, Uint8 defines) :
x86ArgListInstruction (inPrimitive, inPool, uses, defines ),
codeType(inCodeType)
{
iArgumentList = new x86DoubleArgumentList(inArgType1, inArgType2, inDisplacement);
DEBUG_ONLY(debugType = kInsnDoubleOpDir);
// temp for asserts
getDirectionBit();
}
// copy flag should only be set if insn is a copy and the use and define are registerDirect -- no other flags can be set
InstructionFlags InsnDoubleOpDir::
getFlags() const
{
return (codeType == raCopyI && iArgumentList->alIsRegisterDirect()) ? ifCopy : ifNone;
}
bool InsnDoubleOpDir::
getDirectionBit()
{
x86DoubleArgumentList* arglist = (x86DoubleArgumentList*)iArgumentList;
bool arg1isDirect = arglist->akIsArg1Direct();
bool arg2isDirect = arglist->akIsArg2Direct();
assert(arg1isDirect || arg2isDirect); // at least one has to be register direct
bool dirBit;
switch(codeType)
{
case raSaveReg:
// Save Instructions
// saves use (first arg) to stack slot (define)
// mov r1 -> M => mov r1 -> M dir = false
assert(arg1isDirect);
assert(!arg2isDirect);
dirBit = false;
break;
case raCopyI:
// Copy Instructions
/* OLD
// copies use (first arg) to define (second arg)
// mov r1 -> r2 => mov r1 -> r2 dir = false
// mov r1 -> M => mov r1 -> M dir = false
// mov M -> r2 => mov r2 <- M dir = true
// ie direction bit is clear iff argument 1 is registerDirect
dirBit = !arg1isDirect;
break;
*/
// copies use (first arg) to define (second arg)
// mov r1 -> r2 => mov r2 <- r1 dir = true
// mov r1 -> M => mov r1 -> M dir = false
// mov M -> r2 => mov r2 <- M dir = true
// ie direction bit is clear iff argument 1 is registerDirect
dirBit = arg2isDirect;
break;
case raStoreB:
case raStoreH:
case raStoreI:
// Store Instruction
// stores second use into first use memory
// mov M <- r2 => mov r2 -> M dir = false
dirBit = false;
assert(!arg1isDirect);
assert(arg2isDirect);
break;
case raLoadI:
// Load Instruction
// loads from memory address (use, first arg) into register (define, second arg)
// mov M -> r1 => mov r1 <- M dir = true
dirBit = true;
assert(!arg1isDirect);
assert(arg2isDirect);
break;
default:
// Arithmetic Instructions
// add r1, r2 => add r1, r2 dir = true
// add r1, M => add r1, M dir = true
// add M, r2 => add r2, M dir = false
// ie direction bit is set iff argument 1 is registerDirect
assert(raInfo[codeType].type == kArith);
dirBit = arg1isDirect;
}
return dirBit;
}
void InsnDoubleOpDir::
formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter)
{
uint8* start = (uint8*) inStart;
assert(iArgumentList);
// Format the opcode to memory
if(raInfo[codeType].needs16BitPrefix)
*start++ = kPrefix_For_16_Bits;
// calculate opcode
Uint8 direction = getDirectionBit() ? 2 : 0;
Uint8 opcode = raInfo[codeType].opcode | direction;
*start = opcode;
// Find the location of the argumnet list and format it to memory
Uint8* argLocation = (Uint8*)inStart + opcodeSize();
iArgumentList->alFormatToMemory((void*)argLocation , inOffset, *this, inFormatter);
}
Uint8 InsnDoubleOpDir::
opcodeSize()
{
return (raInfo[codeType].needs16BitPrefix) ? 2 : 1;
}
#ifdef DEBUG_LOG
void InsnDoubleOpDir::
printOpcode(LogModuleObject &f)
{
UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%-8s ", raInfo[codeType].text));
}
#endif
//================================================================================

Просмотреть файл

@ -0,0 +1,655 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// x86Win32Instruction.h
//
// Peter DeSantis
// Simon Holmes a Court
#ifndef X86_WIN32_INSTRUCTION
#define X86_WIN32_INSTRUCTION
#include "CatchAssert.h"
#include <stdio.h>
#include "prtypes.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "VirtualRegister.h"
#include "Value.h"
#include "x86Opcode.h"
#include "x86ArgumentList.h"
#include "MemoryAccess.h"
#include "LogModule.h"
#include "NativeCodeCache.h"
#ifdef DEBUG
enum instructionObjType
{
kx86Instruction,
kSetInstruction,
kInsnDoubleOpDir,
kInsnDoubleOp,
kStandardArith,
kStandardArithDisp,
kNotKnown
};
#endif
//================================================================================
/*
x86Instruction(being eliminated) InsnSet
InsnDoubleOp InsnSwitch
InsnDoubleOpDir InsnSysCallCondBranch
| InsnCondBranch
| InsnNoArgs
x86ArglistInstruction Call
\ /
\ /
\ /
InsnUseXDefineYFromPool
|
Instruction (can't spill)
*/
//================================================================================
// x86ArgListInstruction
class x86ArgListInstruction :
public InsnUseXDefineYFromPool
{
public:
x86ArgListInstruction(DataNode* inPrimitive, Pool& inPool, Uint8 inX, Uint8 inY) :
InsnUseXDefineYFromPool (inPrimitive, inPool, inX, inY )
{
DEBUG_ONLY(debugType = kNotKnown);
}
// utility
void x86StandardUseDefine(x86Win32Emitter& inEmitter);
// virtual methods that must be written
virtual Uint8 opcodeSize() = 0;
// defaults to (result of opcodeSize() + iArgumentList->alSize(*this))
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/);
virtual void formatToMemory(void * /*inStart*/, Uint32 /*inCurOffset*/, MdFormatter& /*inFormatter*/) = 0;
// flags
InstructionFlags getFlags() const { return ifNone; }
// spilling
virtual bool switchUseToSpill(Uint8 inWhichUse, VirtualRegister&inVR);
virtual bool switchDefineToSpill(Uint8 inWhichDefine, VirtualRegister& inVR);
// Control Spilling
// eg switch cannot spill (at least for now)
// eg special mem-reg type does funky things when spilling
virtual bool opcodeAcceptsSpill() { return true; } // most instructions can spill
virtual void switchOpcodeToSpill() { } // most opcodes don't change on spilling
// simple arithmetic and move instructions have a direction bit
virtual bool canReverseOperands() { return false; } // most instructions can't reverse their operands
// immediates
virtual bool opcodeCanAccept1ByteImmediate() { return false; }
virtual bool opcodeCanAccept4ByteImmediate() { return false; }
virtual bool opcodeCanAcceptImmediate() { return (opcodeCanAccept1ByteImmediate() || opcodeCanAccept4ByteImmediate()); }
// condensable
virtual bool regOperandCanBeCondensed() { return false; }
protected:
x86ArgumentList* iArgumentList;
public:
#ifdef DEBUG_LOG
// Debugging Methods
virtual void printPretty(LogModuleObject &f);
virtual void printOpcode(LogModuleObject &f) = 0;
#endif // DEBUG_LOG
#ifdef DEBUG
instructionObjType debugType; // used so we know what type of object we are in the debugger
void checkIntegrity() { iArgumentList->alCheckIntegrity(*this); }
void printArgs() { iArgumentList->alPrintArgs(*this); }
#endif // DEBUG
};
inline size_t x86ArgListInstruction::
getFormattedSize(MdFormatter& inFormatter)
{
assert(iArgumentList != NULL);
size_t size = opcodeSize() + iArgumentList->alSize(*this, inFormatter);
return size;
}
#ifdef DEBUG_LOG
inline void x86ArgListInstruction::
printPretty(LogModuleObject &f)
{
printOpcode(f);
assert(iArgumentList != NULL);
iArgumentList->alPrintPretty(f, *this );
}
#endif // DEBUG_LOG
//================================================================================
// x86Instruction
// This mega-class will eventually be phased out as it is split up into smaller classes
class x86Instruction :
public x86ArgListInstruction
{
public:
//--------------------------------------------------------------------------------
// ImmediateArithType Instructions
x86Instruction (DataNode* inPrimitive, Pool& inPool, ControlNode& inControlNode) :
x86ArgListInstruction (inPrimitive, inPool, 0, 0 ) , flags(ifNone)
{
iOpcode = new x86Opcode_ImmArith( iaJmp );
iArgumentList = new x86ControlNodeOffsetArgumentList( inControlNode );
}
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86ImmediateArithType inOpInfo, Uint32 inConstant, x86ArgumentType inArgType1, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{
iOpcode = new x86Opcode_ImmArith( inOpInfo );
iArgumentList = new x86ImmediateArgumentList( inArgType1, inConstant );
}
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86ImmediateArithType inOpInfo, Uint32 inConstant, x86ArgumentType inArgType1, Uint32 inDisplacement, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_ImmArith( inOpInfo );
iArgumentList = new x86ImmediateArgumentList( inArgType1, inDisplacement, inConstant ); }
//--------------------------------------------------------------------------------
// ExtendedType Instructions
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86ExtendedType inOpInfo, Uint32 inConstant, x86ArgumentType inArgType1, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_Reg( inOpInfo );
iArgumentList = new x86ImmediateArgumentList( inArgType1, inConstant ); }
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86ExtendedType inOpInfo, Uint32 inConstant, x86ArgumentType inArgType1, Uint32 inDisplacement, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_Reg( inOpInfo );
iArgumentList = new x86ImmediateArgumentList( inArgType1, inDisplacement, inConstant ); }
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86ExtendedType inOpInfo, x86ArgumentType inArgType1, Uint8 inX, Uint8 inY ) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_Reg( inOpInfo );
iArgumentList = new x86SingleArgumentList( inArgType1 ); }
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86ExtendedType inOpInfo, x86ArgumentType inArgType1, Uint32 inDisplacement, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_Reg( inOpInfo );
iArgumentList = new x86SingleArgumentList( inArgType1, inDisplacement ); }
//--------------------------------------------------------------------------------
// CondensableExtendedType Instructions
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86CondensableExtendedType inOpInfo, Uint32 inConstant, x86ArgumentType inArgType1, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_Condensable_Reg( inOpInfo );
iArgumentList = new x86CondensableImmediateArgumentList( inArgType1, inConstant ); }
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86CondensableExtendedType inOpInfo, x86ArgumentType inArgType1, Uint8 inX, Uint8 inY) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_Condensable_Reg( inOpInfo );
iArgumentList = new x86SingleArgumentList( inArgType1 ); }
//--------------------------------------------------------------------------------
// SpecialRegMemType Instruction
x86Instruction (DataNode* inPrimitive, Pool& inPool, x86SpecialRegMemType inType, Uint32 inImmediate, Uint8 inX, Uint8 inY ) :
x86ArgListInstruction (inPrimitive, inPool, inX, inY ) , flags(ifNone)
{ iOpcode = new x86Opcode_SpecialRegMem( inType );
iArgumentList = new x86SpecialRegMemArgumentList( inImmediate ); }
size_t getFormattedSize(MdFormatter& /*inFormatter*/);
virtual void formatToMemory(void * /*inStart*/, Uint32 /*inCurOffset*/, MdFormatter& /*inFormatter*/);
// access flags
InstructionFlags getFlags() const { return flags; }
void setFlags(InstructionFlags f) { flags = f; }
// Allows ArgumentList access to opcode without passing the extra reference to the opcode.
Uint8 opcodeSize(){ return iOpcode->opSize(); }
bool opcodeCanAccept1ByteImmediate() { return iOpcode->opCanAccept1ByteImmediate(); }
bool opcodeCanAccept4ByteImmediate() { return iOpcode->opCanAccept4ByteImmediate(); }
bool regOperandCanBeCondensed() { return iOpcode->opRegOperandCanBeCondensed(); }
virtual bool opcodeAcceptsSpill() { return true; }
virtual void switchOpcodeToSpill() { iOpcode->opSwitchToRegisterIndirect(); }
protected:
x86Opcode* iOpcode;
InstructionFlags flags; // Used to mark copy instructions so the register allocator can remove them.
public:
#ifdef DEBUG_LOG
void printOpcode(LogModuleObject &f);
#endif // DEBUG_LOG
};
//--------------------------------------------------------------------------------
// FIX these two methods should be removed (third method replaces them)
inline Uint8 useToRegisterNumber(InstructionUse& inUse)
{
return colorTox86GPR[inUse.getVirtualRegister().getColor()];
}
inline Uint8 defineToRegisterNumber(InstructionDefine& inDefine)
{
Uint8 color = inDefine.getVirtualRegister().getColor();
return colorTox86GPR[color];
}
inline Uint8 getRegisterNumber(VirtualRegister* vreg)
{
Uint8 color = vreg->getColor();
assert(color < 6);
return colorTox86GPR[color];
}
//--------------------------------------------------------------------------------
inline size_t x86Instruction::
getFormattedSize(MdFormatter& inFormatter)
{
assert(iOpcode != NULL && iArgumentList != NULL);
return (iOpcode->opSize() + iArgumentList->alSize(*this, inFormatter));
}
#ifdef DEBUG_LOG
inline void x86Instruction::
printOpcode(LogModuleObject &f)
{
iOpcode->opPrintPretty(f);
}
#endif DEBUG_LOG
//================================================================================
// InsnNoArgs
class InsnNoArgs :
public InsnUseXDefineYFromPool
{
public:
InsnNoArgs(DataNode* inPrimitive, Pool& inPool, x86NoArgsCode inCode, Uint8 inUses, Uint8 inDefines) :
InsnUseXDefineYFromPool(inPrimitive, inPool, inUses, inDefines),
code(inCode)
{}
virtual void formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/);
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return 1; }
InstructionFlags getFlags() const { return ifNone; }
virtual bool opcodeAcceptsSpill() { return false; }
virtual void switchOpcodeToSpill() { assert(false); }
protected:
x86NoArgsCode code;
#ifdef DEBUG_LOG
public:
virtual void printPretty(LogModuleObject &f);
#endif
};
//================================================================================
// InsnSwitch
class InsnSwitch :
public InsnUseXDefineYFromPool
{
public:
InsnSwitch(DataNode* inPrimitive, Pool& inPool);
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/);
InstructionFlags getFlags() const { return ifNone; }
// can't spill
virtual bool opcodeAcceptsSpill() { return false; }
virtual void switchOpcodeToSpill() { assert(false); }
protected:
Uint32 mNumCases;
ControlNode* mControlNode;
Uint8* mTableAddress;
#ifdef DEBUG_LOG
public:
virtual void printPretty(LogModuleObject &f);
#endif
};
//================================================================================
// InsnCondBranch
// FIX For now all branches take 4 bytes immediates -- eventually we want this to take
// the minimum possible
class InsnCondBranch :
public InsnUseXDefineYFromPool
{
public:
InsnCondBranch(DataNode* inPrimitive, Pool& inPool, x86ConditionCode condType, ControlNode& inControlNode) :
InsnUseXDefineYFromPool(inPrimitive, inPool, 1, 0),
condType(condType),
cnoSource(inControlNode)
{};
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return 6; }
InstructionFlags getFlags() const { return ifNone; }
virtual bool opcodeAcceptsSpill() { return false; } // spilling makes no sense here
virtual void switchOpcodeToSpill() { assert(false); }
protected:
x86ConditionCode condType; // x86 condition codes
ControlNode& cnoSource; // the source of the branch
#ifdef DEBUG_LOG
public:
virtual void printPretty(LogModuleObject &f);
#endif
};
//================================================================================
// InsnSysCallCondBranch
// emit
// jcc OK
// call inFunc
// OK:
//
class InsnSysCallCondBranch :
public InsnUseXDefineYFromPool
{
public:
InsnSysCallCondBranch(DataNode* inPrimitive, Pool& inPool, x86ConditionCode inCondType, void (*inFunc)()) :
InsnUseXDefineYFromPool(inPrimitive, inPool, 1, 0),
functionAddress(inFunc),
condType(inCondType)
{};
virtual void formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
Uint8* start = (Uint8*) inStart;
// emit jump
*start++ = 0x0f;
*start++ = 0x80 + condType;
writeLittleWordUnaligned((void*)start, 5);
start += 4;
// emit call
Uint8* callStart = start;
*start++ = 0xe8;
int32 branchOffset = (Uint32)functionAddress - (Uint32) callStart - 5;
writeLittleWordUnaligned((void*)start, branchOffset);
}
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return 6 + 5; }
InstructionFlags getFlags() const { return ifNone; }
virtual bool opcodeAcceptsSpill() { return false; } // spilling makes no sense here
virtual void switchOpcodeToSpill() { assert(false); }
protected:
void* functionAddress;
x86ConditionCode condType;
#ifdef DEBUG_LOG
public:
virtual void printPretty(LogModuleObject &f);
#endif
};
//================================================================================
// Set on condition flags
// cannot spill
// uses a condition
class InsnSet :
public InsnUseXDefineYFromPool
{
public:
InsnSet(DataNode* inPrimitive, Pool& inPool, x86ConditionCode condType, int inX = 2, int inY = 1) :
InsnUseXDefineYFromPool(inPrimitive, inPool, inX, inY ),
condType(condType)
{}
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /* inFormatter */ );
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return 3; } // 0xff 0x90 reg
virtual Uint8 opcodeSize() { return 2; }
protected:
x86ConditionCode condType; // x86 condition codes
#ifdef DEBUG_LOG
public:
virtual void printPretty(LogModuleObject &f);
#endif
};
//================================================================================
/* InsnDoubleOp
0110 1001:11 reg1 reg2: immdata register1 with immediate to register2
0110 1001:mod reg r/m: immdata register with immediate to register
0000 1111:1010 1111: 11 reg1 reg2 register1 with register2
0000 1111:1010 1111: mod reg r/m register with memory
*/
class InsnDoubleOp :
public x86ArgListInstruction
{
public:
InsnDoubleOp( DataNode* inPrimitive, Pool& inPool, x86DoubleOpCode inCodeType,
x86ArgumentType inArgType1 = atRegDirect, x86ArgumentType inArgType2 = atRegDirect,
Uint8 uses = 2, Uint8 defines = 1 );
InsnDoubleOp( DataNode* inPrimitive, Pool& inPool, x86DoubleOpCode inCodeType,
Uint32 inDisplacement,
x86ArgumentType inArgType1 = atRegDirect, x86ArgumentType inArgType2 = atRegDirect,
Uint8 uses = 2, Uint8 defines = 1 );
virtual bool canReverseOperands() { return false; }
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter);
virtual Uint8 opcodeSize();
protected:
x86DoubleOpCode codeType;
public:
#ifdef DEBUG_LOG
virtual void printOpcode(LogModuleObject &f);
#endif
};
//================================================================================
// InsnDoubleOpDir
// use the default spilling behaviour for x86ArgListInstruction
class InsnDoubleOpDir :
public x86ArgListInstruction
{
public:
InsnDoubleOpDir(DataNode* inPrimitive, Pool& inPool, x86DoubleOpDirCode inCodeType,
x86ArgumentType inArgType1 = atRegDirect, x86ArgumentType inArgType2 = atRegDirect,
Uint8 uses = 2, Uint8 defines = 1 );
InsnDoubleOpDir(DataNode* inPrimitive, Pool& inPool, x86DoubleOpDirCode inCodeType,
Uint32 inDisplacement,
x86ArgumentType inArgType1 = atRegDirect, x86ArgumentType inArgType2 = atRegDirect,
Uint8 uses = 2, Uint8 defines = 1 );
// the main feature of these instructions is their ability to reverse operands
virtual bool canReverseOperands() { return true; }
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter);
virtual Uint8 opcodeSize();
InstructionFlags getFlags() const; // ifCopy if we are an unspilt move, ifNone otherwise
protected:
bool getDirectionBit();
x86DoubleOpDirCode codeType;
public:
#ifdef DEBUG_LOG
virtual void printOpcode(LogModuleObject &f);
#endif
};
//================================================================================
// Utililty
// Returns a new copy instruction
inline InsnDoubleOpDir&
newCopyInstruction(DataNode& inDataNode, Pool& inPool, Uint8 uses = 1, Uint8 defines = 1)
{
return *new(inPool) InsnDoubleOpDir(&inDataNode, inPool, raCopyI, atRegDirect, atRegDirect, uses, defines);
}
//================================================================================
// Calls
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic>
class Call :
public InsnUseXDefineYFromPool
{
public:
static inline bool hasReturnValue(DataNode& inDataNode);
static inline Uint8 numberOfArguments(DataNode& inDataNode);
Call( DataNode* inDataNode,
Pool& inPool,
Uint8 inRegisterArguments,
bool inHasReturnValue,
x86Win32Emitter& inEmitter,
void (*inFunc)() = NULL,
DataNode* inUseDataNode = NULL );
public:
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return (5); }
virtual InstructionFlags getFlags() const { return (ifCall); }
protected:
Uint32 mCalleeAddress;
#ifdef DEBUG_LOG
public:
virtual void printPretty(LogModuleObject &f)
{
CacheEntry* ce = NativeCodeCache::getCache().lookupByRange((Uint8*)mCalleeAddress);
if(ce)
{
Method* method = ce->descriptor.method;
assert(method);
const char* name = method->getName();
const char* tag = method->getHTMLName();
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" call <A HREF=\"%s\">%s</A>", tag, name));
}
else
UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" call %p", (Uint32 *)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,
x86Win32Emitter& inEmitter,
void (*inFunc)(),
DataNode* inUseDataNode = NULL ) :
Call<tHasIncomingStore, tHasOutgoingStore, false, false>(inDataNode, inPool, inRegisterArguments, inHasReturnValue, inEmitter, inFunc, inUseDataNode) { }
};
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, x86Win32Emitter& inEmitter) :
Call<true, true, true, true>(inDataNode, inPool, inRegisterArguments, inHasReturnValue, inEmitter) { }
inline virtual void formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& inEmitter);
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return (2); }
#ifdef DEBUG_LOG
virtual void printPretty(LogModuleObject &f) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" call ???")); }
#endif
};
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);
}
template<bool tHasIncomingStore, bool tHasOutgoingStore, bool tHasFunctionAddress, bool tIsDynamic>
void Call<tHasIncomingStore, tHasOutgoingStore, tHasFunctionAddress, tIsDynamic>::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
Uint8* start = (Uint8*)inStart;
int32 branchOffset = mCalleeAddress - (Uint32) inStart - 5;
*start++ = 0xe8;
writeLittleWordUnaligned((void*)start, branchOffset);
}
inline void CallD_::
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
{
Uint8 *curPC = (Uint8 *) inStart;
*curPC++ = 0xff;
*curPC++ = 0xd0 | useToRegisterNumber(getInstructionUseBegin()[0]);
}
#endif

Просмотреть файл

@ -0,0 +1,435 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
// File: x86Win32_support.cpp
//
// Authors: Peter DeSantis
// Simon Holmes a Court
//
#include "NativeCodeCache.h"
#include <string.h>
#include "Fundamentals.h"
#include "MemoryAccess.h"
void* JNIenv = 0;
extern ClassWorld world;
#define Naked __declspec( naked )
/*
+-------------------------------+
| return address |
========+===============================+========
| EBP link |
+-------------------------------+
| Saved Non-volatiles |
| eg. EDI |
| ESI |
| EBX |
+-------------------------------+
*/
// Fucntion: staticCompileStub
//
// WARNING: if you change this method, you must change compileStubReEntryPoint below.
// It must point to the instruction after the invokation of compileAndBackPatchMethod
static Naked void staticCompileStub()
{
_asm
{
// remove cache entry from the stack
pop eax
// make frame
push ebp
mov ebp,esp
// save all volatiles (especially for exception handler)
push edi
push esi
push ebx
// call compileAndBackPatchMethod with args
// third argument is not used
push [esp + 16] // second argument -- return address
push eax // first argument -- cacheEntry
call compileAndBackPatchMethod
// remove args
pop edx // <--- compileStubReEntryPoint
pop edx
pop ebx // Restore volatiles
pop esi
pop edi
// remove frame
mov esp,ebp
pop ebp
// jump to the compiled method
push eax // ret will jump to this address
ret // Jump to function leaving the return address at the top of the stack
}
}
#ifdef DEBUG
// Pointer to the instruction after the call (used by exception handler to check
// I wanted to use:
// void* compileStubReEntryPoint = (void*) ((Uint8*)staticCompileStub + 17);
// but MSDev appears to have a bug, in that compileStubReEntryPoint will be set == (void*)staticCompileStub
// which is clearly wrong.
void* compileStubAddress = (void*)staticCompileStub;
void* compileStubReEntryPoint = (Uint8*)compileStubAddress + 17;
#endif // DEBUG
static Naked void compileStub()
{
_asm {
push 0xEFBEADDE // This is a dummy immediate that will be filled in by
jmp staticCompileStub // generateCompileStub with the cacheEntry.
}
}
void *
generateNativeStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry, void *nativeFunction)
{
Method* method = inCacheEntry.descriptor.method;
//Uint32 nWords = method->getSignature().nArguments;
Uint32 nWords = method->getArgsSize()/sizeof(Int32);
assert(method->getModifiers() & CR_METHOD_NATIVE);
assert(nWords <= 256);
extern void *sysInvokeNativeStubs[];
Uint8 stubSize = 10;
void* stub;
// Write out the native stub
stub = inCache.acquireMemory(stubSize);
Uint8* where = (Uint8*)stub;
*where++ = 0x68; // pushl
writeLittleWordUnaligned(where, (uint32)(nativeFunction));
where += 4;
*where++ = 0xe9; // jmp
writeLittleWordUnaligned(where, (Uint8 *) sysInvokeNativeStubs[nWords] - (where + 4));
// Return the address of the stub.
return ((void*)stub);
}
void*
generateCompileStub(NativeCodeCache& inCache, const CacheEntry& inCacheEntry)
{
void* stub;
uint8 stubSize;
uint8 argumentOffset;
uint32 locationOfCompileStub;
stubSize = 10;
// Write out the dynamic compile stub
stub = inCache.acquireMemory(stubSize);
argumentOffset = 1;
locationOfCompileStub = (uint32)compileStub ;
// Copy the stub into the allocated memory
memcpy(stub, (void*)locationOfCompileStub, stubSize);
// Write your cacheEntry into the proper spot in the stub
uint8* loadCacheEntryInstruction = (uint8*)stub + argumentOffset;
writeLittleWordUnaligned((void*)loadCacheEntryInstruction, (uint32)(&inCacheEntry));
// Fix the new dynamic stub to jump to the static stub
uint32* relativeCallLocation = (uint32*)(loadCacheEntryInstruction + 5);
uint32 newRelativeDisplacement = locationOfCompileStub - (uint32)stub + *(uint32*)relativeCallLocation;
writeLittleWordUnaligned((void*)relativeCallLocation, newRelativeDisplacement);
// Return the address of the dynamic stub.
return ((void*)stub);
}
void*
backPatchMethod(void* inMethodAddress, void* inLastPC, void* /*inUserDefined*/)
{
uint32 curAddress = (uint32) inLastPC;
uint32 methodAddress = (uint32) inMethodAddress;
// Compute the relative branch
uint32* relativeBranch = ((uint32*)inLastPC)-1;
int32 offset = methodAddress - curAddress;
// Backpatch the method.
writeLittleWordUnaligned((void*)relativeBranch, offset);
return (inMethodAddress);
}
// Warning silencing stuff
// #pragma warning( disable : 4035)
// #pragma warning( default : 4035)
//================================================================================
// 64bit Arithmetic Support Functions
// x86Extract64Bit
//
// Purpose: signed right-aligned field extraction
// In: 64 bit source (on stack)
// 32 bit extraction size (on stack)
// Out: 64 bit result
// Note: Only works in range 1 <= b <= 63, b is extraction amount
Naked void x86Extract64Bit()
{
__asm
{
mov eax, [esp+4] // load low byte of a
mov ecx, [esp+12] // load shift amount
cmp ecx, 0x20
jg greater32
// extract <= than 32 bits
// shift amount = 32 - extract
neg ecx
add ecx, 0x20 // ecx = 32 - extract
shl eax, cl
sar eax, cl
cdq // sign extend into EDX:EAX
ret 12
greater32:
// ext > 32 bits
// shift amount = 64 - extract
mov edx, [esp+8] // load high byte of a
neg ecx
add ecx, 0x40 // ecx = 64 - extract
shl edx, cl
sar edx, cl
ret 12
}
}
// 3WayCompare
//
// Purpose: compare two longs
// In: two longs on the stack
// Out: depends on condition flags:
// less = -1
// equal = 0
// greater = 1
Naked void x86ThreeWayCMP_L()
{
// edx:eax is tos, ecx:ebx is nos
__asm
{
mov ecx,[esp+8]
mov edx,[esp+16]
cmp ecx,edx
jl lcmp_m1
jg lcmp_1
mov ecx,[esp+4]
mov edx,[esp+12]
cmp ecx,edx
ja lcmp_1
mov eax,0
jb lcmp_m1
ret 16
align 4
lcmp_m1:
mov eax,-1
ret 16
align 4
lcmp_1:
mov eax,1
ret 16
}
}
// 3WayCompare
//
// Purpose: compare two longs
// In: two longs on the stack
// Out: depends on condition flags:
// less = 1
// equal = 0
// greater = -1
Naked void x86ThreeWayCMPC_L()
{
// edx:eax is tos, ecx:ebx is nos
__asm
{
mov ecx,[esp+8]
mov edx,[esp+16]
cmp ecx,edx
jl lcmp_m1
jg lcmp_1
mov ecx,[esp+4]
mov edx,[esp+12]
cmp ecx,edx
ja lcmp_1
mov eax,0
jb lcmp_m1
ret 16
align 4
lcmp_m1:
mov eax,1
ret 16
align 4
lcmp_1:
mov eax,-1
ret 16
}
}
// llmul
//
// Purpose: long multiply (same for signed/unsigned)
// In: args are passed on the stack:
// 1st pushed: multiplier (QWORD)
// 2nd pushed: multiplicand (QWORD)
// Out: EDX:EAX - product of multiplier and multiplicand
// Note: parameters are removed from the stack
// Uses: ECX
Naked void x86Mul64Bit()
{
// IMPLEMENT: Needs to be written
_asm
{
int 3
}
}
// lldiv
//
// Purpose: signed long divide
// In: args are passed on the stack:
// 1st pushed: divisor (QWORD)
// 2nd pushed: dividend (QWORD)
// Out: EDX:EAX contains the quotient (dividend/divisor)
// Note: parameters are removed from the stack
// Uses: ECX
Naked void x86Div64Bit()
{
// IMPLEMENT: Needs to be written
_asm
{
int 3
}
}
// llrem
//
// Purpose: signed long remainder
// In: args are passed on the stack:
// 1st pushed: divisor (QWORD)
// 2nd pushed: dividend (QWORD)
// Out: EDX:EAX contains the quotient (dividend/divisor)
// Note: parameters are removed from the stack
// Uses: ECX
Naked void x86Mod64Bit()
{
// IMPLEMENT: Needs to be written
_asm
{
int 3
}
}
// llshl
//
// Purpose: long shift left
// In: args are passed on the stack: (FIX make fastcall)
// 1st pushed: amount (int)
// 2nd pushed: source (long)
// Out: EDX:EAX contains the result
// Note: parameters are removed from the stack
// Uses: ECX, destroyed
Naked void x86Shl64Bit()
{
// IMPLEMENT: Needs to be written
_asm
{
int 3
}
}
// llshr
//
// Origin: MSDev. modified
// Purpose: long shift right
// In: args are passed on the stack: (FIX make fastcall)
// 1st pushed: amount (int)
// 2nd pushed: source (long)
// Out: EDX:EAX contains the result
// Note: parameters are removed from the stack
// Uses: ECX, destroyed
Naked void x86Shr64Bit()
{
// IMPLEMENT: Needs to be written
_asm
{
int 3
}
}
// llsar
//
// Origin: MSDev. modified
// Purpose: long shift right signed
// In: args are passed on the stack: (FIX make fastcall)
// 1st pushed: amount (int)
// 2nd pushed: source (long)
// Out: EDX:EAX contains the result
// Note: parameters are removed from the stack
// Uses: ECX, destroyed
Naked void x86Sar64Bit()
{
// IMPLEMENT: Needs to be written
_asm
{
int 3
}
}
//================================================================================

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,521 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef BYTECODEGRAPH_H
#define BYTECODEGRAPH_H
#include "DoublyLinkedList.h"
#include "JavaBytecodes.h"
#include "TranslationEnv.h"
#include "VerificationEnv.h"
#include "ControlGraph.h"
#include "ClassFileSummary.h"
#include "LogModule.h"
#include "CheckedUnion.h"
//
// Invariants for a BytecodeGraph:
//
// 1. The BytecodeGraph starts with the beginBlock BytecodeBlock.
//
// 2. The BytecodeGraph contains exactly one EndBlock.
// That block has no bytecodes and no successors.
//
// 3. Every BytecodeBlock whose subkind is not skForward contains at least one bytecode.
// A BytecodeBlock's subkind is skNormal unless specified otherwise below.
// The EndBlock and CatchBlocks contain no bytecodes.
//
// 4. The BytecodeGraph contains at most one BytecodeBlock that contains a return instruction
// (return, ireturn, areturn, etc.). The return instruction must be the only one in that
// BytecodeBlock. That BytecodeBlock must have exactly one successor, the EndBlock, and
// no exceptional successors. That BytecodeBlock's subkind must be skReturn.
//
// 5. An instruction of kind bckIf can only occur if it is the last one in a BytecodeBlock.
// That BytecodeBlock must have exactly two successors, the first of which is the false
// branch and the second the true branch.
//
// 6. An instruction of kind bckGoto or bckGoto_W may occur only if it is the last one in a
// BytecodeBlock. That BytecodeBlock must have exactly one successor.
//
// 7. An instruction of kind bckTableSwitch or bckLookupSwitch may occur only if it is the
// last one in a BytecodeBlock. That BytecodeBlock must have n+1 successors, where n
// is the number of cases. The first successor is the default, while the remaining ones
// correspond to the cases in the order they are listed in the tableswitch or lookupswitch
// instruction.
//
// 8. An instruction of kind bckThrow may occur only if it is the last one in a
// BytecodeBlock. That BytecodeBlock must have no successors.
//
// 9. A jsr (or jsr_w) instruction must be the only one in its BytecodeBlock. That BytecodeBlock
// must have either one or two successors and no exceptional successors. The first successor
// is the first BytecodeBlock of the subroutine (also called the subroutine's header).
// The second successor, if present, is the BytecodeBlock containing instructions after the jsr.
// The second successor is absent if verification determines that the subroutine never returns
// via a BytecodeBlock of kind skRet. The jsr BytecodeBlock's subkind must be skJsr if it has
// two successors or skJsrNoRet if it has one successor.
//
// 10. A ret (or wide ret) instruction must be the only one in its BytecodeBlock. That BytecodeBlock
// must have no successors and no exceptional successors. This BytecodeBlock's subkind must be
// skRet.
//
// 11. A BytecodeBlock with subkind skForward must not have any instructions. That BytecodeBlock
// must have exactly one successor and no exceptional successors and is treated as an
// unconditional branch to that one successor.
//
// 12. No BytecodeBlock may contain an instruction of kind bckIllegal.
//
// 13. Every BytecodeBlock that ends with one of the remaining instructions (kinds bckNormal
// or bckExc) must have exactly one successor.
//
// 14. Exceptional successors are only allowed in BytecodeBlocks that do not contain return,
// ret, or jsr instructions. Every exceptional successor must be either a CatchBlock or the
// EndBlock.
//
// 15. Non-exceptional successors may not refer to a CatchBlock.
//
// 16. The one successor of a CatchBlock must be a BytecodeBlock. That BytecodeBlock's catchBlock
// must point back to that CatchBlock.
//
class BytecodeGraph;
struct BytecodeBlock;
struct BasicBlock: DoublyLinkedEntry<BasicBlock> // Links to other BasicBlocks in the same graph
{
// Persistent fields
enum Kind {bbEnd, bbBytecode, bbCatch};
enum StackNormalization {snNoChange, sn0, sn1, sn2}; // Number of words to leave on the stack when entering a BasicBlock.
// snNoChange means to leave the stack as is (the normal case);
// sn0, sn1, and sn2 mean to leave only the *top* 0, 1, or 2 words on the stack.
// These are needed so we can combine all return bytecodes into one block.
const Kind kind ENUM_8; // Kind of this BasicBlock (EndBlock, BytecodeBlock, or CatchBlock)
const StackNormalization stackNormalization ENUM_8; // Number of words to leave on the stack when entering this BasicBlock
BasicBlock **successorsBegin; // Array of pointers to successors (nil if this is the end block)
BasicBlock **successorsEnd; // Last normal successor pointer + 1; (nil if this is the end block)
// also first exceptional successor pointer
BasicBlock **handlersEnd; // Last exceptional successor pointer + 1 (nil if this is the end block;
#ifdef DEBUG // same as successorsEnd if this is a catch block)
BasicBlock **successorsPhysicalEnd; // End of storage allocated for this successors array
#endif
// Fields computed by depthFirstSearch
enum {unmarked = -3, unvisited = -2, unnumbered = -1};
Int32 dfsNum; // Serial number assigned by depth-first search (-3 is unmarked, -2 is unvisited, -1 is unnumbered)
Uint32 nPredecessors; // Number of BasicBlock successor pointers that refer to this BasicBlock
// (often different from the number of ControlNodes that jump to this
// BasicBlock's ControlNodes because some BasicBlocks may be discovered
// to be dead and hence generate no ControlNodes, while others may generate
// code that has multiple branches to their successors.)
// The beginBlock pointer is also considered to be a successor pointer (so
// nPredecessors of the first block is always at least one).
// The implicit exception edges going to the EndBlock are not counted
#ifdef DEBUG // in the end BasicBlock's nPredecessors.
bool hasIncomingBackEdges; // True if this block has incoming backward edges
#endif
private:
// Temporary fields for verification
struct VerificationTemps
{
Uint32 generation; // Number of last dataflow pass to have changed verificationEnvIn; 0 if none yet
VerificationEnv verificationEnvIn; // State of locals and stack at beginning of block
BytecodeBlock *subroutineHeader; // If this is a ret block, points to the entry point (header) of the subroutine;
// nil if not known or this is not a ret block.
BytecodeBlock *subroutineRet; // If this is a subroutine header, points to the ret block of that subroutine;
// nil if the ret block hasn't been found yet or this is not a subroutine header.
union {
BasicBlock *clone; // The copy of this BasicBlock, temporarily stored here while copying a subgraph of this graph
bool recompute; // True if verificationEnvIn has changed since it was last propagated to successors
};
VerificationTemps(VerificationEnv::Common &c):
generation(0), verificationEnvIn(c), subroutineHeader(0), subroutineRet(0), recompute(false) {}
VerificationTemps(const VerificationEnv &env, Function1<BytecodeBlock *, BytecodeBlock *> &translator,
BytecodeBlock *subroutineHeader, BytecodeBlock *subroutineRet):
generation(0), verificationEnvIn(env, translator), subroutineHeader(subroutineHeader), subroutineRet(subroutineRet) {}
};
// Temporary fields for translation into a primitive graph
struct TranslationTemps
{
Uint32 nSeenPredecessors; // Number of already seen BasicBlock successor pointers that refer to this BasicBlock
TranslationEnv translationEnvIn; // State of locals and stack at beginning of block
// For efficiency, the end block's envIn contains information only about memory bindings.
bool envInInitialized BOOL_8; // True if envIn has already been initialized; if false, no ControlNodes point to
#ifdef DEBUG // firstControlNode yet.
bool generatedControlNodes BOOL_8; // True if ControlNodes have already been generated or optimized out for this BasicBlock
#endif
mutable ControlNode *firstControlNode; // First ControlNode generated for this BasicBlock or nil if none yet or optimized out
DoublyLinkedList<ControlEdge> predecessors; // List of predecessors of this block's first generated control node
// (Moved into firstControlNode when the ControlNodes for this BasicBlock are created.)
TranslationTemps(TranslationCommonEnv &commonEnv);
};
CheckedUnion2(VerificationTemps, TranslationTemps) temps;
public:
BasicBlock(BytecodeGraph &bytecodeGraph, Kind kind, StackNormalization stackNormalization);
bool hasKind(Kind k) const {return k == kind;}
Uint32 nSuccessors() const {return successorsEnd - successorsBegin;}
BytecodeBlock &getSuccessor(Uint32 n) const;
// Accessors for temporary fields for verification
void initVerification(VerificationEnv::Common &c);
void initVerification(BasicBlock &src, Function1<BytecodeBlock *, BytecodeBlock *> &translator);
Uint32 &getGeneration() {return temps.getVerificationTemps().generation;}
VerificationEnv &getVerificationEnvIn() {return temps.getVerificationTemps().verificationEnvIn;}
BytecodeBlock *&getSubroutineHeader() {return temps.getVerificationTemps().subroutineHeader;}
BytecodeBlock *&getSubroutineRet() {return temps.getVerificationTemps().subroutineRet;}
BasicBlock *&getClone() {return temps.getVerificationTemps().clone;}
bool &getRecompute() {return temps.getVerificationTemps().recompute;}
// Accessors for temporary fields for primitive graph translation
void initTranslation(TranslationCommonEnv &commonEnv);
Uint32 &getNSeenPredecessors() {return temps.getTranslationTemps().nSeenPredecessors;}
bool &getEnvInInitialized() {return temps.getTranslationTemps().envInInitialized;}
#ifdef DEBUG
bool getGeneratedControlNodes() const {return temps.getTranslationTemps().generatedControlNodes;}
bool &getGeneratedControlNodes() {return temps.getTranslationTemps().generatedControlNodes;}
#endif
ControlNode *&getFirstControlNode() const {return temps.getTranslationTemps().firstControlNode;}
DoublyLinkedList<ControlEdge> &getPredecessors() {return temps.getTranslationTemps().predecessors;}
public:
TranslationEnv &getTranslationEnvIn() {return temps.getTranslationTemps().translationEnvIn;}
const TranslationEnv &getTranslationEnvIn() const {return temps.getTranslationTemps().translationEnvIn;}
// Debugging
#ifdef DEBUG_LOG
int printRef(LogModuleObject &f, const BytecodeGraph &bg) const;
void printPretty(LogModuleObject &f, const BytecodeGraph &bg, const ConstantPool *c, int margin) const;
#endif
};
struct EndBlock: BasicBlock
{
EndBlock(BytecodeGraph &bytecodeGraph);
};
struct CatchBlock: BasicBlock
{
private:
BasicBlock *successor; // The handler of exceptions caught here
public:
CatchBlock(BytecodeGraph &bytecodeGraph, BytecodeBlock &handler);
CatchBlock(BytecodeGraph &bytecodeGraph, const CatchBlock &src);
BytecodeBlock &getHandler() const;
};
struct BytecodeBlock: BasicBlock
{
enum Subkind
{
skNormal, // A BytecodeBlock that does not contain any return, ret, or jsr instructions
skReturn, // A BytecodeBlock consisting entirely of one of the return instructions
skJsr, // A BytecodeBlock consisting entirely of a jsr or jsr_w instruction whose subroutine may or may not return
skJsrNoRet, // A BytecodeBlock consisting entirely of a jsr or jsr_w instruction whose subroutine is known never to return
skRet, // A BytecodeBlock consisting entirely of a ret or wide ret instruction
skForward // A formerly skRet BytecodeBlock that is known to unconditionally branch to its one successor
};
const bytecode *const bytecodesBegin; // Pointer to first bytecode in this block
const bytecode *bytecodesEnd; // End of last bytecode + 1
CatchBlock *catchBlock; // If a catch handler begins at bytecodesBegin, a CatchBlock that points back to
// this block; nil otherwise.
const Class **exceptionClasses; // Array of exception classes; an exception matching the nth exception class
const Class **exceptionClassesEnd; // would transfer control to the nth exceptional successor
Subkind subkind ENUM_8; // Description of contents of this BytecodeBlock
BytecodeBlock(BytecodeGraph &bytecodeGraph, const bytecode *bytecodesBegin, StackNormalization stackNormalization);
BytecodeBlock(BytecodeGraph &bytecodeGraph, const BytecodeBlock &src);
bool hasSubkind(Subkind sk) const {return sk == subkind;}
bool handlersForbidden() const;
void initSuccessors(BasicBlock **successors, Uint32 nSuccessors, Int32 nActiveHandlers, Pool &bytecodeGraphPool);
BasicBlock **transformToJsrNoRet();
void transformToForward(BasicBlock **successor);
};
class BytecodeGraph
{
public:
// Persistent fields
Pool &bytecodeGraphPool; // Pool for allocating this BytecodeGraph's nodes (blocks)
ClassFileSummary &classFileSummary; // Java class file descriptor
Method& method; // The method this
// BytecodeGraph represents
const Uint32 nLocals; // Number of words of local variables
const Uint32 stackSize; // Number of words of local stack space
const bool isInstanceMethod BOOL_8; // True if this method has a "this" argument
const bool isSynchronized BOOL_8; // True if this method is synchronized
const uint nArguments; // Number of incoming arguments (including "this")
const ValueKind *const argumentKinds; // Kinds of incoming arguments (including "this")
const ValueKind resultKind; // Kind of result
const bytecode *const bytecodesBegin; // Pointer to first bytecode in this function (must be word-aligned)
const bytecode *const bytecodesEnd; // End of last bytecode in this function + 1
const Uint32 bytecodesSize; // bytecodesEnd - bytecodesBegin
const Uint32 nExceptionEntries; // Number of exception table entries
const ExceptionItem *const exceptionEntries;// Exception table
BytecodeBlock *beginBlock; // Starting basic block in function
EndBlock *endBlock; // The end BasicBlock
BytecodeBlock *returnBlock; // The return BytecodeBlock or nil if none
private:
DoublyLinkedList<BasicBlock> blocks; // List of basic blocks (may include unreachable blocks)
Uint32 nBlocks; // Number of reachable basic blocks
// Fields computed by depthFirstSearch
BasicBlock **dfsList; // Array of reachable basic blocks ordered by depth-first search;
// each block's dfsNum is an index into this array.
const bytecode returnBytecode; // The kind of return bytecode that corresponds to resultKind
bool hasBackEdges BOOL_8; // True if this graph contains a cycle
bool hasJSRs BOOL_8; // True if this graph contains a jsr or jsr_w instruction
public:
BytecodeGraph(ClassFileSummary &cfs, Pool &bytecodeGraphPool, bool isInstanceMethod, bool isSynchronized,
uint nArguments, const ValueKind *argumentKinds, ValueKind resultKind, Uint32 nLocals, Uint32 stackSize,
const bytecode *bytecodesBegin, Uint32 bytecodesSize, Uint32 nExceptionEntries,
const ExceptionItem *exceptionEntries, Method& method);
private:
BytecodeGraph(const BytecodeGraph &); // Copying forbidden
void operator=(const BytecodeGraph &); // Copying forbidden
public:
BasicBlock **getDFSList() const {assert(dfsList); return dfsList;}
Uint32 getDFSListLength() const {assert(dfsList); return nBlocks;}
void invalidateDFSList() {DEBUG_ONLY(dfsList = 0);}
void addBlock(BasicBlock &block) {blocks.addLast(block); invalidateDFSList();}
static const bytecode *switchAlign(const bytecode *bc);
private:
BytecodeBlock &followGotos(Uint32 initialOffset, Int32 displacement, BytecodeBlock **blocks);
BytecodeBlock &noteBlockBoundary(Uint32 offset, BytecodeBlock **blocks);
void noteExceptionBoundaries(BytecodeBlock **blocks, Int32 *activeHandlerDeltas);
const bytecode *noteTableSwitchTargets(const bytecode *bc, BytecodeBlock **blocks);
const bytecode *noteLookupSwitchTargets(const bytecode *bc, BytecodeBlock **blocks);
const bytecode *recordTableSwitchTargets(const bytecode *bc, BytecodeBlock **blocks, BasicBlock **&successors,
Uint32 &nSuccessors, Int32 nActiveHandlers);
const bytecode *recordLookupSwitchTargets(const bytecode *bc, BytecodeBlock **blocks, BasicBlock **&successors,
Uint32 &nSuccessors, Int32 nActiveHandlers);
void recordHandlerTargets(BytecodeBlock **blocks);
void verifyNoBoundariesBetween(const bytecode *bc1, const bytecode *bc2, BytecodeBlock **blocks) const;
void createBlocks(Pool &tempPool);
bool depthFirstSearch(Pool &tempPool);
void splitCatchNodes();
public:
void divideIntoBlocks(Pool &tempPool);
#ifdef DEBUG_LOG
bool dfsBlockNumbersValid() const {return dfsList != 0;}
void print(LogModuleObject &f, const ConstantPool *c) const;
#endif
};
// --- INLINES ----------------------------------------------------------------
//
// Initialize BasicBlock fields used for translation into a primitive graph.
//
inline BasicBlock::TranslationTemps::TranslationTemps(TranslationCommonEnv &commonEnv):
nSeenPredecessors(0),
translationEnvIn(commonEnv),
envInInitialized(false),
firstControlNode(0)
{
#ifdef DEBUG
generatedControlNodes = false;
#endif
}
//
// Initialize this BasicBlock contained in the given BytecodeGraph.
//
inline BasicBlock::BasicBlock(BytecodeGraph &bytecodeGraph, Kind kind, StackNormalization stackNormalization):
kind(kind),
stackNormalization(stackNormalization)
{
bytecodeGraph.addBlock(*this);
}
//
// Return the nth regular (non-exceptional) successor.
// Don't call this to get the successor of the return node, because it is not
// a BytecodeBlock.
//
inline BytecodeBlock &BasicBlock::getSuccessor(Uint32 n) const
{
assert(n < nSuccessors() && successorsBegin[n]->hasKind(bbBytecode));
return *static_cast<BytecodeBlock *>(successorsBegin[n]);
}
//
// Prepare this BasicBlock for verification.
//
inline void BasicBlock::initVerification(VerificationEnv::Common &c)
{
new(temps.initVerificationTemps()) VerificationTemps(c);
}
//
// Prepare this BasicBlock for verification using a copy of src's env, subroutineHeader,
// and subroutineRet fields. Translate any BasicBlock pointers using the given
// translator. Set the generation to zero.
//
inline void BasicBlock::initVerification(BasicBlock &src, Function1<BytecodeBlock *, BytecodeBlock *> &translator)
{
new(temps.initVerificationTemps()) VerificationTemps(src.getVerificationEnvIn(), translator,
translator(src.getSubroutineHeader()), translator(src.getSubroutineRet()));
}
//
// Prepare this BasicBlock for translation into a primitive graph.
//
inline void BasicBlock::initTranslation(TranslationCommonEnv &commonEnv)
{
new(temps.initTranslationTemps()) TranslationTemps(commonEnv);
}
//
// Initialize this CatchBlock contained in the given BytecodeGraph.
// The CatchBlock's successor is given.
//
inline CatchBlock::CatchBlock(BytecodeGraph &bytecodeGraph, BytecodeBlock &handler):
BasicBlock(bytecodeGraph, bbCatch, sn0),
successor(&handler)
{
successorsBegin = &successor;
successorsEnd = &successor + 1;
handlersEnd = successorsEnd;
#ifdef DEBUG
successorsPhysicalEnd = handlersEnd;
#endif
}
//
// Make a copy of the src CatchBlock pointing to the same handler as src and add it
// to the given graph. However, do not copy or initialize the VerificationTemps or
// TranslationTemps in the copy.
//
inline CatchBlock::CatchBlock(BytecodeGraph &bytecodeGraph, const CatchBlock &src):
BasicBlock(bytecodeGraph, bbCatch, sn0),
successor(src.successor)
{
successorsBegin = &successor;
successorsEnd = &successor + 1;
handlersEnd = successorsEnd;
#ifdef DEBUG
successorsPhysicalEnd = handlersEnd;
#endif
}
//
// Return the handler passed to this CatchBlock's constructor.
//
inline BytecodeBlock &CatchBlock::getHandler() const
{
return *static_cast<BytecodeBlock *>(successor);
}
//
// Initialize this BytecodeBlock contained in the given BytecodeGraph.
// The caller should later call initSuccessors to set up this block's successors.
//
inline BytecodeBlock::BytecodeBlock(BytecodeGraph &bytecodeGraph, const bytecode *bytecodesBegin, StackNormalization stackNormalization):
BasicBlock(bytecodeGraph, bbBytecode, stackNormalization),
bytecodesBegin(bytecodesBegin),
catchBlock(0),
subkind(skNormal)
{}
//
// Return true if this block must not have any handlers and createBlocks should not
// allocates any room for handlers.
//
inline bool BytecodeBlock::handlersForbidden() const
{
return !hasSubkind(skNormal);
}
//
// Change this skJsr block to a skJsrNoRet block. Return a pointer suitable as an
// argument to transformToForward.
//
inline BasicBlock **BytecodeBlock::transformToJsrNoRet()
{
assert(hasSubkind(skJsr));
subkind = skJsrNoRet;
BasicBlock **e = successorsEnd - 1;
successorsEnd = e;
handlersEnd = e;
#ifdef DEBUG
successorsPhysicalEnd = e;
#endif
return e;
}
//
// Change this skRet block to a skForward block. successor must point to a one-word
// block of memory allocated from this bytecode graph's pool that points to this block's
// unique successor.
//
inline void BytecodeBlock::transformToForward(BasicBlock **successor)
{
assert(hasSubkind(skRet));
subkind = skForward;
successorsBegin = successor;
BasicBlock **e = successor + 1;
successorsEnd = e;
handlersEnd = e;
#ifdef DEBUG
successorsPhysicalEnd = e;
#endif
bytecodesEnd = bytecodesBegin;
}
//
// Return bc word-aligned as needed for a tableswitch or lookupswitch bytecode.
//
inline const bytecode *BytecodeGraph::switchAlign(const bytecode *bc)
{
// Assumes that bytecodesBegin is word-aligned.
return (const bytecode *)((size_t)bc + 3 & -4);
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef BYTECODETRANSLATOR_H
#define BYTECODETRANSLATOR_H
#include "BytecodeGraph.h"
class BytecodeTranslator: public TranslationCommonEnv
{
// Helper for translating a BytecodeBlock
class BlockTranslator
{
const BytecodeTranslator &bt; // Backpointer to the current BytecodeTranslator
Pool &envPool; // The pool for allocating translation environment parts (disappears after primitives are generated)
Pool &primitivePool; // The pool for allocating new parts of the primitive graph
ClassFileSummary &classFileSummary; // The BytecodeGraph's ClassFileSummary
TranslationEnv *translationEnv; // The current state of local and stack variables; never nil
BytecodeBlock &block; // The block which we're currently translating
ControlNode *cn; // The control node currently being generated or nil if we are done
public:
BlockTranslator(const BytecodeTranslator &bt, TranslationEnv &env, BytecodeBlock &block, ControlNode *cn);
TranslationEnv &getEnv() const {return *translationEnv;}
void setEnv(TranslationEnv &env) {translationEnv = &env;}
ControlGraph &getControlGraph() const {return bt.controlGraph;}
private:
void appendControlNode(ControlEdge &e);
void genException(ControlKind ck, Primitive *tryPrimitive, const Class &exceptionClass, bool canOwnEnv) const;
void genThrowCommon(const VariableOrConstant &exception, const Class &exceptionClass, bool canOwnEnv);
void genSimpleThrow(cobj exceptionObject, bool canOwnEnv);
void genPossibleThrow(Primitive &prim, const Class &exceptionClass);
void createBasicBlock(BasicBlock &successor);
void createIf(Condition2 cond2, bool reverseCond2,
VariableOrConstant &c, BasicBlock &successorFalse,
BasicBlock &successorTrue, Uint32 bci);
void createContinuedIf(Condition2 cond2, bool reverseCond2,
VariableOrConstant &c,
BasicBlock &successorTrue, Uint32 bci);
void genNullGuard(const VariableOrConstant &arg, Uint32 bci);
void genTableSwitch(const bytecode *bc, Uint32 bci);
void genLookupSwitch(const bytecode *bc, Uint32 bci);
void genReadObjectType(const VariableOrConstant &object,
VariableOrConstant &type, Uint32 bci) const;
void genGetStatic(ConstantPoolIndex cpi, Uint32 bci) const;
void genPutStatic(ConstantPoolIndex cpi, Uint32 bci) const;
void genGetField(ConstantPoolIndex cpi, Uint32 bci);
void genPutField(ConstantPoolIndex cpi, Uint32 bci);
void genReadArrayLength(const VariableOrConstant &arrayAddr, VariableOrConstant &arrayLength, Uint32 bci);
void genArrayCastGuard(const VariableOrConstant &array, const VariableOrConstant &object);
void genArrayEltAccess(TypeKind tk, bool write, Uint32 bci);
void genCheckInterfaceAssignability(VariableOrConstant &type, const Type &targetInterface, VariableOrConstant *results, Uint32 bci) const;
void genCheckCastNonNull(const Type &t, const VariableOrConstant &arg, Uint32 bci);
void genCheckCast(ConstantPoolIndex cpi, const VariableOrConstant &arg, Uint32 bci);
void genInstanceOfNonNull(const Type &t, const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *cnFalse, Uint32 bci);
void genInstanceOf(ConstantPoolIndex cpi, const VariableOrConstant &arg, VariableOrConstant &result, Uint32 bci);
void genNewCommon(const SysCall &sysCall, uint nArgs, const VariableOrConstant *args, Uint32 bci);
void genTempArrayOfDim(Int32 dim, Uint32 bci);
Primitive &genMonitor(PrimitiveOperation op, const VariableOrConstant &arg, Uint32 bci) const;
void genThrow(const VariableOrConstant &exception);
void genReceiverNullCheck(const Signature &sig, VariableOrConstant &receiver, Uint32 bci);
void genVirtualLookup(const VariableOrConstant &receiver, Uint32 vIndex, VariableOrConstant &functionAddr, Uint32 bci) const;
void genInterfaceLookup(const VariableOrConstant &receiver, Uint32 interfaceNumber, Uint32 vIndex, const Method *method,
VariableOrConstant &functionAddr, Uint32 bci) const;
void genInvoke(bytecode opcode, ConstantPoolIndex cpi, uint nArgs, Uint32 bci);
public:
void genLivePrimitives();
void genCycleHeader();
#ifdef DEBUG
bool translatorDone() const {return !cn;}
#endif
};
BytecodeGraph &bytecodeGraph; // The BytecodeGraph from which we're translating
ControlGraph &controlGraph; // The primitive graph to which we're translating
BytecodeTranslator(BytecodeGraph &bytecodeGraph, ControlGraph &controlGraph, Pool &envPool);
static void normalizeEnv(TranslationEnv &env, BasicBlock::StackNormalization stackNormalization);
static void linkPredecessor(BasicBlock &block, ControlEdge &controlEdge, TranslationEnv &predecessorEnv, bool canOwnEnv);
static void finishedOnePredecessor(BasicBlock &block);
static void finishedOutgoingEdges(BasicBlock &block);
ControlNode *createControlNode(BasicBlock &block, bool mergeBlock) const;
void genPrimitives(EndBlock &block) const;
void genPrimitives(CatchBlock &block) const;
void genPrimitives(BytecodeBlock &block) const;
void genRawPrimitiveGraph() const;
void addSynchronization(VariableOrConstant &syncHolder, Uint32 bci) const;
public:
static ControlGraph *genPrimitiveGraph(BytecodeGraph &bytecodeGraph, Pool &primitivePool, Pool &tempPool);
friend class BytecodeTranslator::BlockTranslator; // BlockTranslator calls the private methods above
};
// --- INLINES ----------------------------------------------------------------
//
// Initialize a translator that will translate a single BytecodeBlock.
//
inline BytecodeTranslator::BlockTranslator::BlockTranslator(const BytecodeTranslator &bt, TranslationEnv &env, BytecodeBlock &block,
ControlNode *cn):
bt(bt),
envPool(bt.envPool),
primitivePool(bt.primitivePool),
classFileSummary(bt.bytecodeGraph.classFileSummary),
translationEnv(&env),
block(block),
cn(cn)
{}
//
// Initialize a translator that will construct the control graph out of the given
// bytecode graph.
// envPool will be used for temporary allocation of TranslationEnvs and the data
// structures they contain; all of these can be deallocated when the BytecodeTranslator
// is done.
//
inline BytecodeTranslator::BytecodeTranslator(BytecodeGraph &bytecodeGraph, ControlGraph &controlGraph, Pool &envPool):
TranslationCommonEnv(envPool, controlGraph.pool, bytecodeGraph.nLocals, bytecodeGraph.stackSize),
bytecodeGraph(bytecodeGraph),
controlGraph(controlGraph)
{}
//
// Take note that we just completely generated code for a BasicBlock b
// that is one of the predecessors of BasicBlock block. If b jumps to
// BasicBlock block, then BasicBlock block's environment should have been
// adjusted accordingly by now.
// This method lets BasicBlock block keep track of how many other
// BasicBlocks remain that can jump to BasicBlock block and whose
// environments have not yet been merged into BasicBlock block.
//
inline void BytecodeTranslator::finishedOnePredecessor(BasicBlock &block)
{
assert(block.getNSeenPredecessors() != block.nPredecessors);
block.getNSeenPredecessors()++;
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef BYTECODEVERIFIER_H
#define BYTECODEVERIFIER_H
#include "BytecodeGraph.h"
#include "Tree.h"
// A data structure for keeping track of all call sites for each subroutine.
// Only includes mappings for skJsr call sites; skJsrNoRet call sites are deleted
// from this association list as soon as they are discovered not to have a ret.
class SubroutineCallSiteList
{
struct Association
{
BytecodeBlock &subroutine; // A subroutine (never nil) ...
BytecodeBlock *const callSite; // ... and one of its call sites (may be nil)
Association(BytecodeBlock &subroutine, BytecodeBlock &callSite): subroutine(subroutine), callSite(&callSite) {}
explicit Association(BytecodeBlock &subroutine): subroutine(subroutine), callSite(0) {}
bool operator<(const Association &a2) const;
};
class Node: public TreeNode<Node>
{
Association association; // An association of a subroutine with one of its call sites
public:
explicit Node(Association &association): association(association) {}
const Association &getKey() const {return association;}
};
public:
class Iterator
{
BytecodeBlock &subroutine; // The subroutine whose call sites we're iterating
Node *node; // The node currently at the iterator's position or nil if none
public:
Iterator(SubroutineCallSiteList &csList, BytecodeBlock &subroutine);
bool more() const {return node != 0;}
BytecodeBlock &operator*() const {assert(node); return *node->getKey().callSite;}
void operator++();
};
private:
SortedTree<Node, const Association &> tree; // The actual container of all associations in this SubroutineCallSiteList
public:
void addAssociation(BytecodeBlock &subroutine, BytecodeBlock &callSite, Pool &pool);
void removeAssociation(BytecodeBlock &subroutine, BytecodeBlock &callSite);
BytecodeBlock *popAssociation(BytecodeBlock *&subroutine, bool &onlyOneCallSite);
friend class Iterator;
};
class BytecodeVerifier: public VerificationEnv::Common
{
BytecodeGraph &bytecodeGraph; // The BytecodeGraph which we're examining
ClassFileSummary &classFileSummary; // The BytecodeGraph's ClassFileSummary
SubroutineCallSiteList subroutineCallSiteList; // A mapping from subroutines to their call sites
BytecodeVerifier(BytecodeGraph &bytecodeGraph, Pool &envPool);
// Inlining subroutines
void normalizeEnv(VerificationEnv &env, BasicBlock::StackNormalization stackNormalization);
bool predecessorChanged(BasicBlock &block, VerificationEnv &predecessorEnv, Uint32 generation, bool canOwnEnv);
bool predecessorChanged(BasicBlock **blocksBegin, BasicBlock **blocksEnd, VerificationEnv &predecessorEnv,
Uint32 generation, bool canOwnEnv);
bool propagateDataflow(CatchBlock &block, Uint32 generation);
bool propagateDataflow(BytecodeBlock &block, Uint32 generation);
void computeDataflow();
void computeRetReachables();
void duplicateSubroutines();
public:
static void inlineSubroutines(BytecodeGraph &bytecodeGraph, Pool &tempPool);
};
#endif

Просмотреть файл

@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "ErrorHandling.h"
#ifdef DEBUG
char* verifyErrorString[] =
{
"Unknown cause",
"Functionality not implemented yet",
"Error in reading class file: file not found, or has errors",
"Badly formatted class file",
"Class does not have permissions to access a particular field/method",
"Field not found in class",
"Method not found in class",
"No bytecodes in a function",
"Bad bytecode opcode",
"Bad offset to a bytecode instruction",
"Bad type passed to newarray instruction",
"Constant pool index out of range",
"Wrong return instruction used in this function",
"Bad tableswitch or lookupswitch bytecode",
"More than one ret bytecode for the same subroutine",
"Recursive call to a subroutine or multiple returns from the same subroutine",
"Bad combination of types in a bytecode",
"Attempt to pop from an empty bytecode stack",
"Attempt to push onto a full bytecode stack",
"Stack depth at a point differs based on how execution got there",
"Index of local variable out of range",
"Attempt to write to a constant (final) field",
"Given class not found in class file",
"Catch filter class not a subclass of Throwable",
"Class can be its own superclass",
"Compiler internal limits reached",
"Attempt to invoke abstract method",
"Binary incompatibility / incompatibleClassChange"
};
char* runtimeErrorString[] =
{
"Unknown cause",
"Internal error",
"Functionality not implemented yet",
"incorrect argument to a method",
"prohibited operation",
"Security violation",
"IO Error",
"fileNotFound",
"Unable to link method",
"Null Pointer argument",
"Attempt to instantiate an abstract class"
};
#endif
//
// This is called when there's something wrong with a class.
//
NS_EXTERN void
verifyError(VerifyError::Cause cause)
{
#ifdef DEBUG
fprintf(stderr, "\n*** VERIFY ERROR *** [%d] %s\n", cause, verifyErrorString[cause]);
#endif
#ifdef __GNUC__
exit(cause);
#endif
throw VerifyError(cause);
}
//
// This is called when there is an error during runtime.
//
NS_EXTERN void
runtimeError(RuntimeError::Cause cause)
{
#ifdef DEBUG
fprintf(stderr, "\n*** RUNTIME ERROR *** [%d] %s\n", cause, runtimeErrorString[cause]);
#endif
#ifdef __GNUC__
exit(cause);
#endif
throw RuntimeError(cause);
}

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef ERRORHANDLING_H
#define ERRORHANDLING_H
#include "NativeDefs.h"
struct VerifyError
{
enum Cause
{
unknown, // Unknown cause
notImplemented, // Functionality not implemented yet
noClassDefFound, // Error in reading class file: file not found, or has errors
badClassFormat, // Badly formatted class file
illegalAccess, // Class does not have permissions to access a particular field/method
noSuchField, // Field not found in class
noSuchMethod, // Method not found in class
noBytecodes, // No bytecodes in a function
badBytecode, // Bad bytecode opcode
badBytecodeOffset, // Bad offset to a bytecode instruction
badNewArrayType, // Bad type passed to newarray instruction
badConstantPoolIndex, // Constant pool index out of range
badReturn, // Wrong return instruction used in this function
badSwitchBytecode, // Bad tableswitch or lookupswitch bytecode
multipleRet, // More than one ret bytecode for the same subroutine
jsrNestingError, // Recursive call to a subroutine or multiple returns from the same subroutine
badType, // Bad combination of types in a bytecode
bytecodeStackUnderflow, // Attempt to pop from an empty bytecode stack
bytecodeStackOverflow, // Attempt to push onto a full bytecode stack
bytecodeStackDynamic, // Stack depth at a point differs based on how execution got there
noSuchLocal, // Index of local variable out of range
writeToConst, // Attempt to write to a constant (final) field
classNotFound, // Given class not found in class file
nonThrowableCatch, // Catch filter class not a subclass of Throwable
classCircularity, // Class can be its own superclass
resourceExhausted, // Compiler internal limits reached
abstractMethod, // Attempt to invoke abstract method
incompatibleClassChange // Binary incompatibility
};
const Cause cause;
VerifyError(Cause cause): cause(cause) {}
};
NS_EXTERN
void verifyError(VerifyError::Cause cause);
struct RuntimeError
{
enum Cause
{
unknown, // Unknown cause
internal, // Internal error
notImplemented, // Functionality not implemented yet
illegalArgument, // incorrect argument to a method
illegalAccess, // prohibited operation
securityViolation, // Security violation
IOError, // IO Error
fileNotFound,
linkError, // Unable to link method
nullPointer, // Null Pointer argument
notInstantiable // Attempt to instantiate an abstract class
};
const Cause cause;
RuntimeError(Cause cause): cause(cause) {}
};
NS_EXTERN
void runtimeError(RuntimeError::Cause cause);
#endif

Просмотреть файл

@ -0,0 +1,215 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef LOCALENV_H
#define LOCALENV_H
#include "Fundamentals.h"
// Information common to all environments in a graph
struct CommonEnv
{
Pool &envPool; // Memory pool from which to allocate
const Uint32 nLocals; // Number of words of local variables
const Uint32 stackBase; // Index of first stack temporary
const Uint32 stackSize; // Number of words of local stack space
const Uint32 nEnvSlots; // nMemoryBindings + nLocals + stackSize
CommonEnv(Pool &envPool, Uint32 nMemoryBindings, Uint32 nLocals, Uint32 stackSize):
envPool(envPool), nLocals(nLocals), stackBase(nMemoryBindings + nLocals), stackSize(stackSize),
nEnvSlots(nMemoryBindings + nLocals + stackSize) {}
};
// A single environment containings bindings of class Binding.
// Class Common, which should be derived from CommonEnv, contains information
// common to all environments in a graph.
template<class Binding, class Common, Uint32 nMemoryBindings>
class LocalEnv
{
protected:
const Common &commonEnv; // Backpointer to information shared among all LocalEnvs in a graph
private:
Binding *bindings; // Array of:
// nMemoryBindings memory bindings
// nLocals local variable bindings
// stackSize stack temporaries' bindings
// (the bindings may be nil).
Uint32 sp; // Stack pointer (index within bindings array of first unused temporary)
// Bindings at indices 0..sp-1 are valid; others are ignored
public:
explicit LocalEnv(const Common &commonEnv);
LocalEnv(const LocalEnv &env): commonEnv(env.commonEnv) {copyEnv(env);}
void operator=(const LocalEnv &env) {assert(!bindings); copyEnv(env);}
void move(LocalEnv &env);
void init();
protected:
void copyEnv(const LocalEnv &env);
Binding *bindingsBegin() const {return bindings;} // Return the first valid binding
Binding *bindingsEnd() const {return bindings + sp;} // Return the last valid binding + 1
Binding *bindingsMemoryEnd() const {return bindings + nMemoryBindings;} // Return the last memory binding + 1
public:
Pool &envPool() const {return commonEnv.envPool;}
Binding &memory() const {return bindings[0];}
Binding &local(Uint32 n) const {assert(n < commonEnv.nLocals); return bindings[nMemoryBindings + n];}
Binding &stackNth(Uint32 n) const {assert(n > 0 && sp >= commonEnv.stackBase + n); return bindings[sp - n];}
Binding *stackTopN(Uint32 DEBUG_ONLY(n)) const {assert(sp >= commonEnv.stackBase + n); return bindings + sp;}
// Stack operations
Uint32 getSP() const {return sp - commonEnv.stackBase;}
void dropAll() {sp = commonEnv.stackBase;}
void drop(uint n) {assert(sp >= commonEnv.stackBase + n); sp -= n;}
void raise(uint n) {assert(sp + n <= commonEnv.nEnvSlots); sp += n;}
Binding &pop() {assert(sp > commonEnv.stackBase); return bindings[--sp];} // Note: Result invalidated by next push!
Binding &push() {assert(sp < commonEnv.nEnvSlots); return bindings[sp++];}
Binding &pop2();
Binding &push2();
Binding &pop1or2(bool two);
Binding &push1or2(bool two);
protected:
bool compatible(const LocalEnv &env) {return bindings && env.bindings && &commonEnv == &env.commonEnv && sp == env.sp;}
};
// --- INLINES ----------------------------------------------------------------
//
// Construct a new LocalEnv for the method described by commonEnv.
// The LocalEnv cannot be used unless init is called first or another LocalEnv
// is copied to this one.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
inline LocalEnv<Binding, Common, nMemoryBindings>::LocalEnv(const Common &commonEnv):
commonEnv(commonEnv),
bindings(0)
{}
//
// Destructively move the given LocalEnv (which must have been initialized)
// to this LocalEnv, which must be uninitialized. The given LocalEnv is
// left uninitialized.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
inline void LocalEnv<Binding, Common, nMemoryBindings>::move(LocalEnv &env)
{
assert(!bindings && env.bindings);
bindings = env.bindings;
sp = env.sp;
#ifdef DEBUG
env.bindings = 0;
#endif
}
//
// Pop and return a long or double binding from the stack. The two words on the top of
// the stack must contain a long or double value.
// Note that the returned reference will be invalidated by the next push.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::pop2()
{
assert(sp > commonEnv.stackBase+1 && bindings[sp-1].isSecondWord());
return bindings[sp -= 2];
}
//
// Push a long or double binding outo the stack. The return value is a reference to
// a new stack slot; the caller must initialize it to refer to the long or double's first word.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::push2()
{
assert(sp < commonEnv.nEnvSlots-1);
Binding *b = &bindings[sp];
b[1].defineSecondWord();
sp += 2;
return *b;
}
//
// Do pop() if two is false or pop2() if two is true.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::pop1or2(bool two)
{
assert(sp > commonEnv.stackBase+two && (!two || bindings[sp-1].isSecondWord()));
if (two)
--sp;
return bindings[--sp];
}
//
// Do push() if two is false or push2() if two is true.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::push1or2(bool two)
{
assert(sp < commonEnv.nEnvSlots-two);
Binding &b = bindings[sp++];
if (two)
bindings[sp++].defineSecondWord();
return b;
}
// --- TEMPLATES --------------------------------------------------------------
//
// Initialize every entry in this LocalEnv to be empty and the stack to have no
// temporaries. This LocalEnv must not have been initialized before.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
void LocalEnv<Binding, Common, nMemoryBindings>::init()
{
assert(!bindings);
Binding *lb = new(commonEnv.envPool) Binding[commonEnv.nEnvSlots];
bindings = lb;
Uint32 stackBase = commonEnv.stackBase;
sp = stackBase;
Binding *lbEnd = lb + stackBase;
while (lb != lbEnd)
lb++->clear();
}
//
// Assign a copy of the given LocalEnv (which must have been initialized)
// to this LocalEnv, which is known to be uninitialized.
//
template<class Binding, class Common, Uint32 nMemoryBindings>
void LocalEnv<Binding, Common, nMemoryBindings>::copyEnv(const LocalEnv &env)
{
assert(env.bindings);
Binding *lbDst = new(commonEnv.envPool) Binding[commonEnv.nEnvSlots];
copy(env.bindingsBegin(), env.bindingsEnd(), lbDst);
bindings = lbDst;
sp = env.sp;
}
#endif

Просмотреть файл

@ -0,0 +1,67 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ../..
CPPSRCS = BytecodeGraph.cpp \
TranslationEnv.cpp \
ErrorHandling.cpp \
BytecodeTranslator.cpp \
VerificationEnv.cpp \
BytecodeVerifier.cpp \
$(NULL)
LOCAL_EXPORTS = BytecodeGraph.h \
BytecodeTranslator.h \
BytecodeVerifier.h \
ErrorHandling.h \
LocalEnv.h \
TranslationEnv.h \
VerificationEnv.h \
$(NULL)
MODULE_NAME = EF
#######################################################################
# (2) Include "component" configuration information. #
#######################################################################
include $(DEPTH)/config/config.mk
#######################################################################
# (3) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#######################################################################
# (4) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################

Просмотреть файл

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef READER_H
#define READER_H
#include "NativeDefs.h"
struct VerifyError
{
enum Cause
{
unknown, // Unknown cause
notImplemented, // Functionality not implemented yet
noClassDefFound, // Error in reading class file: file not found, or has errors
badClassFormat, // Badly formatted class file
illegalAccess, // Class does not have permissions to access a particular field/method
noSuchField, // Field not found in class
noSuchMethod, // Method not found in class
noBytecodes, // No bytecodes in a function
badBytecode, // Bad bytecode opcode
badBytecodeOffset, // Bad offset to a bytecode instruction
badNewArrayType, // Bad type passed to newarray instruction
badConstantPoolIndex, // Constant pool index out of range
badReturn, // Wrong return instruction used in this function
writeToConst, // Attempt to write to a constant (final) field
classNotFound, // Given class not found in class file
nonThrowableCatch, // Catch filter class not a subclass of Throwable
classCircularity, // Class can be its own superclass
resourceExhausted, // Compiler internal limits reached
abstractMethod, // Attempt to invoke abstract method
incompatibleClassChange // Binary incompatibility
};
const Cause cause;
VerifyError(Cause cause): cause(cause) {}
};
NS_EXTERN
void verifyError(VerifyError::Cause cause);
struct RuntimeError
{
enum Cause
{
unknown, // Unknown cause
internal, // Internal error
notImplemented, // Functionality not implemented yet
illegalArgument, // incorrect argument to a method
illegalAccess, // prohibited operation
securityViolation, // Security violation
IOError, // IO Error
fileNotFound,
linkError, // Unable to link method
nullPointer, // Null Pointer argument
notInstantiable, // Attempt to instantiate an abstract class
outOfMemory
};
const Cause cause;
RuntimeError(Cause cause): cause(cause) {}
};
NS_EXTERN
void runtimeError(RuntimeError::Cause cause);
#endif

Просмотреть файл

@ -0,0 +1,516 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "BytecodeGraph.h"
// ----------------------------------------------------------------------------
// TranslationCommonEnv
//
// Create a new, empty phi node in the block's first control node.
// nExpectedInputs is the estimated number of inputs that the phi node will
// eventually have; however, there is no guarantee that the actual number of
// inputs won't be higher or lower.
// This method disengages the phi nodes in the block's first control node
// and must be balanced by a call to finishPhiNode.
//
PhiNode *TranslationCommonEnv::genEmptyPhiNode(const BasicBlock &block, ValueKind kind, Uint32 nExpectedInputs) const
{
PhiNode *phiNode = new(primitivePool) PhiNode(nExpectedInputs, kind, primitivePool);
ControlNode *cn = block.getFirstControlNode();
assert(cn);
cn->disengagePhis();
cn->addPhiNode(*phiNode);
return phiNode;
}
//
// Balance a call to genEmptyPhiNode. The caller should have set up the
// (formerly) empty phi node's inputs by now.
//
inline void TranslationCommonEnv::finishPhiNode(const BasicBlock &block) const
{
ControlNode *cn = block.getFirstControlNode();
assert(cn);
cn->reengagePhis();
}
// ----------------------------------------------------------------------------
// TranslationBinding
//
// Create the real constant primitive node for this Constant. Allocate the
// primitive node out of the given pool.
//
void TranslationBinding::Constant::genRealNode(Pool &primitivePool, Uint32 bci)
{
assert(!producerExists);
PrimConst *primConst = new(primitivePool) PrimConst(kind, value, bci);
placeForDataNode->appendPrimitive(*primConst);
producerExists = true;
dataNode = primConst;
}
//
// Create a new PhantomPhi record with room for size arguments. Ouf of these,
// set the first nInitialArgs (which may be zero) to initialArgs, and set the
// next argument to arg. Clearly, nInitialArgs must be less than size.
// container is the BasicBlock in which this phantom phi node is defined.
// If alwaysNonzero is true, the value of the PhantomPhi is known to never be
// zero.
// Allocate needed storage from pool.
//
TranslationBinding::PhantomPhi::PhantomPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs,
const TranslationBinding &arg, const BasicBlock &container, bool alwaysNonzero, Pool &pool):
container(container),
nArgs(nInitialArgs + 1),
realPhiExists(false),
kind(kind),
alwaysNonzero(alwaysNonzero)
{
TranslationBinding *a = new(pool) TranslationBinding[size];
args = a;
while (nInitialArgs--)
*a++ = initialArgs;
*a = arg;
}
//
// Return true if the value of this PhantomPhi is known to never be zero.
//
bool TranslationBinding::PhantomPhi::isAlwaysNonzero() const
{
return realPhiExists ? realPhi->isAlwaysNonzero() : alwaysNonzero;
}
//
// Inform this PhantomPhi about whether its value is never zero.
//
void TranslationBinding::PhantomPhi::setAlwaysNonzero(bool nz)
{
if (realPhiExists)
realPhi->setAlwaysNonzero(nz);
else
alwaysNonzero = nz;
}
//
// Append a new argument arg to this PhantomPhi's array. If expand is true,
// the array first needs to be physically expanded to size newSize (which is
// guaranteed to hold all of its elements).
//
void TranslationBinding::PhantomPhi::append(bool expand, Uint32 newSize,
const TranslationBinding &arg,
Uint32 bci)
{
if (realPhiExists) {
Pool &primitivePool = container.getTranslationEnvIn().getCommonEnv().primitivePool;
realPhi->addInput(arg.extract(primitivePool, bci), primitivePool);
} else {
Uint32 n = nArgs;
if (expand) {
TranslationBinding *newArgs = new(container.getTranslationEnvIn().envPool()) TranslationBinding[newSize];
copy(args, args + n, newArgs);
args = newArgs;
assert(newSize > n);
}
args[n] = arg;
nArgs = n + 1;
if (alwaysNonzero)
alwaysNonzero = arg.isAlwaysNonzero();
}
}
//
// Create the real phi node for this PhantomPhi.
//
void TranslationBinding::PhantomPhi::genRealPhi(Uint32 bci)
{
assert(!realPhiExists);
TranslationBinding *a = args;
const TranslationEnv &env = container.getTranslationEnvIn();
const TranslationCommonEnv &commonEnv = env.getCommonEnv();
Pool &primitivePool = commonEnv.primitivePool;
Uint32 n = getNArgs();
// Carefully create a new phi node before calling extract on the arguments
// because one of the arguments could refer back to this phi node.
realPhi = commonEnv.genEmptyPhiNode(container, kind, env.getPhiSize());
realPhiExists = true;
while (n--)
realPhi->addInput(a++->extract(primitivePool, bci), primitivePool);
commonEnv.finishPhiNode(container);
}
//
// Return the kind of value represented by this binding.
//
ValueKind TranslationBinding::getKind() const
{
switch (category) {
case tbConstant:
return constant->kind;
case tbDataEdge:
return dataNode->getKind();
case tbPhantomPhi:
case tbConstantPhi:
return phantomPhi->kind;
default:
return vkVoid;
}
}
//
// Return true if the value of this binding is known to never be zero.
//
bool TranslationBinding::isAlwaysNonzero() const
{
switch (category) {
case tbConstant:
return constant->isNonzero();
case tbDataEdge:
return dataNode->isAlwaysNonzero();
case tbPhantomPhi:
case tbConstantPhi:
return phantomPhi->isAlwaysNonzero();
default:
return true;
}
}
//
// Bind this TranslationBinding to represent the given int constant.
// If a primitive to explicitly generate the constant is needed, it will
// be placed in the given ControlNode.
// Allocate needed storage from pool.
//
void TranslationBinding::defineInt(Int32 v, ControlNode *placeForDataNode, Pool &pool)
{
category = tbConstant;
Constant *c = new(pool) Constant(vkInt, placeForDataNode);
c->value.i = v;
constant = c;
}
//
// Bind this TranslationBinding to represent the first word of the given long constant.
// If a primitive to explicitly generate the constant is needed, it will
// be placed in the given ControlNode.
// Allocate needed storage from pool.
//
void TranslationBinding::defineLong(Int64 v, ControlNode *placeForDataNode, Pool &pool)
{
category = tbConstant;
Constant *c = new(pool) Constant(vkLong, placeForDataNode);
c->value.l = v;
constant = c;
}
//
// Bind this TranslationBinding to represent the given float constant.
// If a primitive to explicitly generate the constant is needed, it will
// be placed in the given ControlNode.
// Allocate needed storage from pool.
//
void TranslationBinding::defineFloat(Flt32 v, ControlNode *placeForDataNode, Pool &pool)
{
category = tbConstant;
Constant *c = new(pool) Constant(vkFloat, placeForDataNode);
c->value.f = v;
constant = c;
}
//
// Bind this TranslationBinding to represent the first word of the given double constant.
// If a primitive to explicitly generate the constant is needed, it will
// be placed in the given ControlNode.
// Allocate needed storage from pool.
//
void TranslationBinding::defineDouble(Flt64 v, ControlNode *placeForDataNode, Pool &pool)
{
category = tbConstant;
Constant *c = new(pool) Constant(vkDouble, placeForDataNode);
c->value.d = v;
constant = c;
}
//
// Bind this TranslationBinding to represent the given pointer constant.
// If a primitive to explicitly generate the constant is needed, it will
// be placed in the given ControlNode.
// Allocate needed storage from pool.
//
void TranslationBinding::definePtr(addr v, ControlNode *placeForDataNode, Pool &pool)
{
category = tbConstant;
Constant *c = new(pool) Constant(vkAddr, placeForDataNode);
c->value.a = v;
constant = c;
}
//
// Bind this TranslationBinding to represent the constant (or first word of the constant
// if it takes two words).
// If a primitive to explicitly generate the constant is needed, it will
// be placed in the given ControlNode.
// Allocate needed environment storage from pool.
//
void TranslationBinding::define(ValueKind kind, const Value &v, ControlNode *placeForDataNode, Pool &pool)
{
category = tbConstant;
Constant *c = new(pool) Constant(kind, placeForDataNode);
c->value = v;
constant = c;
}
// ----------------------------------------------------------------------------
// TranslationEnv
#ifdef DEBUG
//
// Assert that none of the PhantomPhi or ConstantPhi nodes referring to the current container
// are shared.
//
void TranslationEnv::assertNoSharedPhantomPhis(const BasicBlock &container)
{
TranslationBinding *dst = bindingsBegin();
TranslationBinding *dstEnd = bindingsEnd();
for (; dst != dstEnd; dst++)
if (dst->category == TranslationBinding::tbPhantomPhi || dst->category == TranslationBinding::tbConstantPhi)
dst->phantomPhi->duplicate = false;
for (dst = bindingsBegin(); dst != dstEnd; dst++)
if (dst->category == TranslationBinding::tbPhantomPhi || dst->category == TranslationBinding::tbConstantPhi) {
TranslationBinding::PhantomPhi *phi = dst->phantomPhi;
assert(&phi->getContainer() != &container || !phi->duplicate);
phi->duplicate = true;
}
}
#endif
//
// Intersect the given TranslationEnv (which must have been initialized)
// into this TranslationEnv, which must also be initialized.
// This environment must be part of the given container.
// If memoryOnly is true, only intersect the memory binding.
//
void TranslationEnv::meet(const TranslationEnv &env, bool memoryOnly, const BasicBlock &container)
{
#ifdef DEBUG
assert(this == &container.getTranslationEnvIn());
assert(compatible(env));
assertNoSharedPhantomPhis(container);
#endif
TranslationBinding *dst = bindingsBegin();
TranslationBinding *dstEnd = memoryOnly ? bindingsMemoryEnd() : bindingsEnd();
const TranslationBinding *src = env.bindingsBegin();
Pool &pool = commonEnv.envPool;
Uint32 oldPhiOffset = phiOffset;
Uint32 newPhiSize = phiSize;
bool expandThis = false;
if (oldPhiOffset >= newPhiSize) {
newPhiSize = oldPhiOffset*2 + 1;
expandThis = true;
}
while (dst != dstEnd) {
TranslationBinding::Category cDst = dst->category;
TranslationBinding::Category cSrc = src->category;
ValueKind kind;
if (cSrc == TranslationBinding::tbNone) {
assert(!anticipated || cDst == TranslationBinding::tbNone);
dst->clear();
} else
switch (cDst) {
case TranslationBinding::tbNone:
break;
case TranslationBinding::tbSecondWord:
if (cSrc != TranslationBinding::tbSecondWord) {
assert(!anticipated);
dst->clear();
}
break;
case TranslationBinding::tbConstantPhi:
{
TranslationBinding::ConstantPhi *phi = dst->constantPhi;
kind = phi->kind;
if (src->getKind() != kind) {
assert(!anticipated);
dst->clear();
break;
}
const TranslationBinding::Constant *srcConstant = src->constantValue();
bool constantMatches = srcConstant && *phi->constant == *srcConstant;
if (&phi->getContainer() == &container)
if (constantMatches)
// asharma - fix this!
phi->append(expandThis, newPhiSize, *src, 0);
else {
// The constant doesn't match, so turn this into a regular phantom phi node.
assert(!anticipated);
dst->category = TranslationBinding::tbPhantomPhi;
goto phantomPhi;
}
else
// Don't merge if both source and destination are the same and they don't refer to
// this container.
if (cSrc != TranslationBinding::tbConstantPhi || src->constantPhi != phi)
if (constantMatches) {
assert(!anticipated);
dst->define(new(pool) TranslationBinding::ConstantPhi(kind, newPhiSize, oldPhiOffset,
*dst, *src, container, srcConstant, pool));
} else
goto createPhi;
}
break;
case TranslationBinding::tbPhantomPhi:
if (src->getKind() != dst->phantomPhi->kind) {
assert(!anticipated);
dst->clear();
break;
}
phantomPhi:
{
TranslationBinding::PhantomPhi *phi = dst->phantomPhi;
if (&phi->getContainer() == &container) {
// Use existing phantom phi node in this node
assert(!phi->isAlwaysNonzero() || src->isAlwaysNonzero() || !anticipated);
// asharma - fix this!
phi->append(expandThis, newPhiSize, *src, 0);
break;
}
// Don't merge if both source and destination are the same and they don't refer to
// this container.
if (cSrc != TranslationBinding::tbPhantomPhi || src->phantomPhi != phi) {
kind = phi->kind;
goto createPhi;
}
}
break;
case TranslationBinding::tbDataEdge:
if (cSrc != TranslationBinding::tbDataEdge || src->dataNode != dst->dataNode) {
kind = dst->dataNode->getKind();
if (src->getKind() != kind) {
assert(!anticipated);
dst->clear();
break;
}
createPhi:
assert(!anticipated);
dst->define(new(pool) TranslationBinding::PhantomPhi(kind, newPhiSize, oldPhiOffset, *dst, *src, container,
dst->isAlwaysNonzero() && src->isAlwaysNonzero(), pool));
}
break;
case TranslationBinding::tbConstant:
if (cSrc != TranslationBinding::tbConstant || src->constant != dst->constant) {
kind = dst->constant->kind;
if (src->getKind() != kind) {
assert(!anticipated);
dst->clear();
break;
}
const TranslationBinding::Constant *srcConstant = src->constantValue();
if (srcConstant && *dst->constant == *srcConstant) {
dst->define(new(pool) TranslationBinding::ConstantPhi(kind, newPhiSize, oldPhiOffset,
*dst, *src, container, srcConstant, pool));
break;
}
goto createPhi;
}
}
src++;
dst++;
}
phiOffset = oldPhiOffset + 1;
phiSize = newPhiSize;
}
//
// Add phantom phi nodes to all variables in this local environment because we'd like
// to use this environment without knowing all of its predecessors yet.
// This environment must be part of the given container.
//
void TranslationEnv::anticipate(const BasicBlock &container)
{
#ifdef DEBUG
assert(this == &container.getTranslationEnvIn());
assertNoSharedPhantomPhis(container);
assert(!anticipated);
anticipated = true;
#endif
TranslationBinding *dst = bindingsBegin();
TranslationBinding *dstEnd = bindingsEnd();
Pool &pool = commonEnv.envPool;
while (dst != dstEnd) {
switch (dst->category) {
case TranslationBinding::tbNone:
case TranslationBinding::tbSecondWord:
break;
case TranslationBinding::tbConstantPhi:
if (&dst->constantPhi->getContainer() != &container)
goto createPhi;
dst->constantPhi->setAlwaysNonzero(false);
dst->category = TranslationBinding::tbPhantomPhi;
break;
case TranslationBinding::tbPhantomPhi:
if (&dst->phantomPhi->getContainer() == &container)
break; // We already have an appropriate phi node.
// Fall into default case because we need to create a new phi node; the current
// value was a phi node from another control node.
default:
createPhi:
assert(phiOffset > 0 && phiSize >= phiOffset);
dst->define(new(pool) TranslationBinding::PhantomPhi(dst->getKind(), phiSize, phiOffset-1,
*dst, *dst, container, false, pool));
break;
}
dst++;
}
}

Просмотреть файл

@ -0,0 +1,465 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef TRANSLATIONENV_H
#define TRANSLATIONENV_H
#include "ControlNodes.h"
#include "LocalEnv.h"
struct BasicBlock;
struct TranslationCommonEnv: CommonEnv
{
Pool &primitivePool; // Pool for allocating phi and constant data flow nodes
PhiNode *genEmptyPhiNode(const BasicBlock &block, ValueKind kind, Uint32 nExpectedInputs) const;
void finishPhiNode(const BasicBlock &block) const;
TranslationCommonEnv(Pool &envPool, Pool &primitivePool, Uint32 nLocals, Uint32 stackSize):
CommonEnv(envPool, 1, nLocals, stackSize), primitivePool(primitivePool) {}
};
class TranslationBinding
{
public:
enum Category
{
tbNone, // Unknown contents
tbSecondWord, // This variable is the second word of a long or double
tbConstant, // This variable is a constant constVal defined in basic block definer
tbDataEdge, // This variable was defined by the given DataNode
tbPhantomPhi, // This variable was defined by the given phantom phi node
tbConstantPhi // This variable was defined by the given phantom phi node that always evaluates to a constant
};
static bool isPhi(Category c) {return c == tbPhantomPhi || c == tbConstantPhi;}
private:
struct Constant
{
const ValueKind kind ENUM_8; // Kind of constant
bool producerExists BOOL_8; // If true, a data flow node exists for this constant and can be found
//short unused SHORT_16; // using dataNode below. If false, the data flow node can be created
union { // in the placeForDataNode control node if needed.
ControlNode *placeForDataNode; // Control node inside which the constant was defined
DataNode *dataNode; // Link to data flow node that defined this constant
};
Value value; // Constant's value
Constant(ValueKind kind, ControlNode *placeForDataNode);
bool operator==(const Constant &c) const {ValueKind k = kind; return k == c.kind && value.eq(k, c.value);}
bool operator!=(const Constant &c) const {ValueKind k = kind; return k != c.kind || !value.eq(k, c.value);}
private:
void genRealNode(Pool &primitivePool, Uint32 bci);
public:
bool isNonzero() const {return value.isNonzero(kind);}
DataNode &realize(Pool &primitivePool, Uint32 bci);
};
class PhantomPhi
{
const BasicBlock &container; // Block in which this phantom phi node is defined
Uint32 nArgs; // Number of occupied arguments in the args array below (valid only when realPhiExists is false)
bool realPhiExists BOOL_8; // If true, a real phi node exists and can be found using realPhi below.
public:
const ValueKind kind ENUM_8; // Kind of value stored in this phi node
DEBUG_ONLY(bool duplicate BOOL_8;) // Flag used for assertNoSharedPhantomPhis
private:
bool alwaysNonzero BOOL_8; // If true, the value of this PhantomPhi is known to always be nonzero
union { // (valid only if realPhiExists is false)
TranslationBinding *args; // Array of phiSize TranslationBinding records for the arguments of a phantom phi node
PhiNode *realPhi; // Real phi node if one has been generated
};
PhantomPhi(const PhantomPhi &); // Copying forbidden
void operator=(const PhantomPhi &); // Copying forbidden
public:
PhantomPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs, const TranslationBinding &arg,
const BasicBlock &container, bool alwaysNonzero, Pool &pool);
const BasicBlock &getContainer() const {return container;}
Uint32 getNArgs() const {assert(!realPhiExists); return nArgs;}
bool isAlwaysNonzero() const;
void setAlwaysNonzero(bool nz);
void append(bool expand, Uint32 newSize,
const TranslationBinding &arg, Uint32 bci);
private:
void genRealPhi(Uint32 bci);
public:
DataNode &realize(Uint32 bci);
};
// A ConstantPhi is a PhantomPhi with the added restriction that all of its arguments are
// either the same constant or other ConstantPhis of the same constant.
struct ConstantPhi: PhantomPhi
{
const Constant *constant; // Constant to which all of the arguments of this phantom phi node evaluate
ConstantPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs, const TranslationBinding &arg,
const BasicBlock &container, const Constant *constant, Pool &pool);
};
Category category ENUM_8; // TranslationBinding category (determines interpretation of union below)
//bool unused BOOL_8;
//short unused SHORT_16;
union {
Constant *constant; // Constant value (Constant may be shared among different bindings)
DataNode *dataNode; // Place where this variable is defined
PhantomPhi *phantomPhi; // Phantom phi node (PhantomPhi may be shared among different bindings)
ConstantPhi *constantPhi; // Phantom phi node all of whose arguments evaluate to the same constant (may be shared)
void *data; // Used for comparing constNum, constAddr, etc.
// Note: The phantomPhi and constantPhi pointers from several different bindings in an environment
// may point to a common PhantomPhi or ConstantPhi record under the following circumstances:
// 1. phantomPhi->container (or constantPhi->container) is not the current environment's container
// 2. All calls to meet and anticipate have completed (at this point sharing can be
// introduced, for instance, by assigning one local to another).
// Sharing of PhantomPhi or ConstantPhi records in the current environment while meet or
// anticipate is running would cause trouble because these routines extend the phantom phi arrays.
};
public:
bool operator==(const TranslationBinding &b) const
{return category == b.category && data == b.data;}
bool operator!=(const TranslationBinding &b) const
{return category != b.category || data != b.data;}
bool isDataEdge() const { return category == tbDataEdge; }
bool isSecondWord() const {return category == tbSecondWord;}
const Constant *constantValue() const;
ValueKind getKind() const;
bool isAlwaysNonzero() const;
void extract(VariableOrConstant &result, Uint32 bci) const;
DataNode &extract(Pool &primitivePool, Uint32 bci) const;
DataNode &extract(Uint32 bci) const;
void clear();
inline void defineSecondWord();
void defineInt(Int32 v, ControlNode *placeForDataNode, Pool &pool);
void defineLong(Int64 v, ControlNode *placeForDataNode, Pool &pool);
void defineFloat(Flt32 v, ControlNode *placeForDataNode, Pool &pool);
void defineDouble(Flt64 v, ControlNode *placeForDataNode, Pool &pool);
void definePtr(addr v, ControlNode *placeForDataNode, Pool &pool);
void define(ValueKind kind, const Value &v, ControlNode *placeForDataNode, Pool &pool);
void define(DataNode &dataNode);
void define(const VariableOrConstant &poc, ControlNode *placeForDataNode, Pool &pool);
private:
void define(PhantomPhi *p) {category = tbPhantomPhi; phantomPhi = p;}
void define(ConstantPhi *p) {category = tbConstantPhi; constantPhi = p;}
friend class TranslationEnv;
};
class TranslationEnv: public LocalEnv<TranslationBinding, TranslationCommonEnv, 1>
{
Uint32 phiSize; // Number of LocalBindings allocated in this environment's phantom phi bindings
Uint32 phiOffset; // Next index to be allocated in this environment's phantom phi bindings
#ifdef DEBUG
bool anticipated; // True if anticipate has been called on this environment
#endif
public:
TranslationEnv(TranslationCommonEnv &commonEnv);
TranslationEnv(const TranslationEnv &env);
void operator=(const TranslationEnv &env);
void move(TranslationEnv &env);
Uint32 getPhiSize() const {return phiSize;}
const TranslationCommonEnv &getCommonEnv() const {return commonEnv;}
#ifdef DEBUG
void assertNoSharedPhantomPhis(const BasicBlock &container);
#endif
void meet(const TranslationEnv &env, bool memoryOnly, const BasicBlock &container);
void anticipate(const BasicBlock &container);
};
// --- INLINES ----------------------------------------------------------------
//
// Initialize a Constant of the given kind. The constant starts out with no
// real data flow node, but if one is needed, it will be created in placeForDataNode.
//
inline TranslationBinding::Constant::Constant(ValueKind kind, ControlNode *placeForDataNode):
kind(kind),
producerExists(false),
placeForDataNode(placeForDataNode)
{
assert(placeForDataNode);
// Prevent this ControlNode from being recycled because a real data flow node could be
// created in it at any time.
placeForDataNode->inhibitRecycling();
}
//
// Create if necessary and return a real data flow node for this constant.
// Allocate the primitive node out of the given pool.
//
inline DataNode &TranslationBinding::Constant::realize(Pool &primitivePool,
Uint32 bci)
{
if (!producerExists)
genRealNode(primitivePool, bci);
return *dataNode;
}
//
// Create if necessary and return the real phi node for this PhantomPhi.
//
inline DataNode &TranslationBinding::PhantomPhi::realize(Uint32 bci)
{
if (!realPhiExists)
genRealPhi(bci);
return *realPhi;
}
//
// Create a new ConstantPhi record with room for size arguments. Ouf of these,
// set the first nInitialArgs (which may be zero) to initialArgs, and set the
// next argument to arg. Clearly, nInitialArgs must be less than size.
// container is the BasicBlock in which this constant phantom phi node is defined.
// Every argument of this ConstantPhi must evaluate to constant.
// Allocate needed storage from pool.
//
inline TranslationBinding::ConstantPhi::ConstantPhi(ValueKind kind, Uint32 size, Uint32 nInitialArgs, const TranslationBinding &initialArgs,
const TranslationBinding &arg, const BasicBlock &container, const Constant *constant, Pool &pool):
PhantomPhi(kind, size, nInitialArgs, initialArgs, arg, container, constant->isNonzero(), pool),
constant(constant)
{}
//
// If this TranslationBinding would always evaluate to the same constant, return that
// constant; otherwise, return nil.
//
inline const TranslationBinding::Constant *TranslationBinding::constantValue() const
{
switch (category) {
case tbConstant:
return constant;
case tbConstantPhi:
return constantPhi->constant;
default:
return 0;
}
}
//
// If this TranslationBinding would always evaluate to the same constant, return that
// constant in result. Otherwise, return the producer in result, creating phi
// nodes for the producer if necessary.
//
inline void TranslationBinding::extract(VariableOrConstant &result,
Uint32 bci) const
{
const Constant *c;
switch (category) {
case tbConstant:
c = constant;
result.setConstant(c->kind, c->value);
break;
case tbDataEdge:
result.setVariable(*dataNode);
break;
case tbPhantomPhi:
result.setVariable(phantomPhi->realize(bci));
break;
case tbConstantPhi:
c = constantPhi->constant;
result.setConstant(c->kind, c->value);
break;
default:
trespass("Can't extract this binding");
}
}
//
// Return the producer for this TranslationBinding, creating phi nodes or
// constant nodes if necessary. Create a producer even if it's just a
// constant.
//
inline DataNode &
TranslationBinding::extract(Pool &primitivePool, Uint32 bci) const
{
switch (category) {
case tbConstant:
return constant->realize(primitivePool, bci);
case tbPhantomPhi:
case tbConstantPhi:
return phantomPhi->realize(bci);
case tbDataEdge:
return *dataNode;
default:
trespass("Can't extract this binding");
return *(DataNode *)0;
}
}
//
// Return the producer for this TranslationBinding, creating phi nodes if
// necessary. It is an error if the producer is a constant.
//
inline DataNode &TranslationBinding::extract(Uint32 bci) const
{
switch (category) {
case tbPhantomPhi:
case tbConstantPhi:
return phantomPhi->realize(bci);
case tbDataEdge:
return *dataNode;
default:
trespass("Can't extract this binding");
return *(DataNode *)0;
}
}
//
// Clear any previous binding from this TranslationBinding.
//
inline void TranslationBinding::clear()
{
category = tbNone;
data = 0;
}
//
// Bind this TranslationBinding to represent the second word of a long or double.
// This TranslationBinding won't carry any more descriptive information about that
// long or double -- all such information is carried by the first word's binding.
//
inline void TranslationBinding::defineSecondWord()
{
category = tbSecondWord;
data = 0;
}
//
// Bind this TranslationBinding to be the result (first word if it's a long or double)
// of the given DataNode.
//
inline void TranslationBinding::define(DataNode &dataNode)
{
category = tbDataEdge;
TranslationBinding::dataNode = &dataNode;
}
//
// Bind this TranslationBinding to be the result (first word if it's a long or double)
// of the given DataNode or Constant.
// Allocate needed environment storage from pool.
//
inline void TranslationBinding::define(const VariableOrConstant &poc, ControlNode *placeForDataNode, Pool &pool)
{
if (poc.isConstant())
define(poc.getKind(), poc.getConstant(), placeForDataNode, pool);
else
define(poc.getVariable());
}
// ----------------------------------------------------------------------------
const initialPhiSize = 3;
//
// Create a new translation binding environment.
// The environment starts with one predecessor for the purpose of tracking
// the origins of phi nodes' entries.
//
inline TranslationEnv::TranslationEnv(TranslationCommonEnv &commonEnv):
LocalEnv<TranslationBinding, TranslationCommonEnv, 1>(commonEnv),
phiSize(initialPhiSize),
phiOffset(1)
#ifdef DEBUG
, anticipated(false)
#endif
{}
//
// Copy a translation binding environment.
// The copy starts with one predecessor for the purpose of tracking
// the origins of phi nodes' entries.
//
inline TranslationEnv::TranslationEnv(const TranslationEnv &env):
LocalEnv<TranslationBinding, TranslationCommonEnv, 1>(env),
phiSize(initialPhiSize),
phiOffset(1)
#ifdef DEBUG
, anticipated(false)
#endif
{}
//
// Assign the given translation binding environment to this one.
// The copy starts with one predecessor for the purpose of tracking
// the origins of phi nodes' entries.
//
inline void TranslationEnv::operator=(const TranslationEnv &env)
{
phiSize = initialPhiSize;
phiOffset = 1;
#ifdef DEBUG
anticipated = false;
#endif
LocalEnv<TranslationBinding, TranslationCommonEnv, 1>::operator=(env);
}
//
// Destructively move the given LocalEnv (which must have been initialized)
// to this LocalEnv, which must be uninitialized. The given LocalEnv is
// left uninitialized.
// The moved environment is reset to have only one predecessor for the purpose
// of tracking the origins of phi nodes' entries.
//
inline void TranslationEnv::move(TranslationEnv &env)
{
phiSize = initialPhiSize;
phiOffset = 1;
#ifdef DEBUG
anticipated = false;
#endif
LocalEnv<TranslationBinding, TranslationCommonEnv, 1>::move(env);
}
#endif

Просмотреть файл

@ -0,0 +1,657 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "VerificationEnv.h"
const VerificationEnv::BindingKind VerificationEnv::valueKindBindingKinds[nValueKinds] =
{
bkVoid, // vkVoid
bkInt, // vkInt
bkLong, // vkLong
bkFloat, // vkFloat
bkDouble, // vkDouble
bkAddr, // vkAddr
bkVoid, // vkCond
bkVoid, // vkMemory
bkVoid // vkTuple
};
const VerificationEnv::BindingKind VerificationEnv::typeKindBindingKinds[nTypeKinds] =
{
bkVoid, // tkVoid
bkInt, // tkBoolean
bkInt, // tkUByte
bkInt, // tkByte
bkInt, // tkChar
bkInt, // tkShort
bkInt, // tkInt
bkLong, // tkLong
bkFloat, // tkFloat
bkDouble, // tkDouble
bkAddr, // tkObject
bkAddr, // tkSpecial
bkAddr, // tkArray
bkAddr // tkInterface
};
// ----------------------------------------------------------------------------
// VerificationEnv::Context
//
// Create a new, empty Context that holds information about which variables a subroutine
// has modified. Clear the modified array (indicating that no variables have been accessed
// yet) and the link to the next context.
//
VerificationEnv::Context::Context(Subroutine subroutine, const Common &common):
next(0),
subroutine(subroutine),
retReachable(false)
#ifdef DEBUG
, common(common)
#endif
{
assert(common.bindingPool);
modified = new(*common.bindingPool) char[common.nEnvSlots];
fill(modified, modified + common.nEnvSlots, 0);
}
//
// Create a copy of the given context. Clear the link to the next context.
//
VerificationEnv::Context::Context(const Context &src, const Common &common):
next(0),
subroutine(src.subroutine),
retReachable(src.retReachable)
#ifdef DEBUG
, common(common)
#endif
{
assert(common.bindingPool);
modified = new(*common.bindingPool) char[common.nEnvSlots];
copy(src.modified, src.modified + common.nEnvSlots, modified);
}
//
// Create a partial copy of the given context. Do not copy the contents of the
// modified array. Translate the Subroutine value using the given translator.
// Clear the link to the next context.
//
inline VerificationEnv::Context::Context(const Context &src, const Common &common, Function1<Subroutine, Subroutine> &translator):
next(0),
subroutine(translator(src.subroutine)),
retReachable(src.retReachable)
#ifdef DEBUG
, common(common)
#endif
{}
//
// Merge this context with the src context. A slot in the merged context is
// set to the modified state if it was modified in either this or the src context.
// Return true if the resulting context differs from the original contents of this
// context.
//
bool VerificationEnv::Context::meet(const Context &src, Uint32 nSlots)
{
assert(subroutine == src.subroutine && common.bindingPool);
bool changed = false;
char *dstModified = modified;
const char *srcModified = src.modified;
for (Uint32 slot = 0; slot != nSlots; slot++)
if (srcModified[slot] && !dstModified[slot]) {
dstModified[slot] = true;
changed = true;
}
return changed;
}
//
// If a context corresponding to the given subroutine is in the linked list of
// contexts, return that context. If not, return nil. list can be nil.
//
VerificationEnv::Context *VerificationEnv::Context::find(Context *list, const Subroutine subroutine)
{
while (list && list->subroutine != subroutine)
list = list->next;
return list;
}
// ----------------------------------------------------------------------------
// VerificationEnv
const VerificationEnv::InitBinding VerificationEnv::secondWordBinding(bkSecondWord);
//
// Assign a partial copy of the given VerificationEnv (which must have been initialized)
// to this VerificationEnv, which is known to be uninitialized. Do not copy the
// bindings nor the modified arrays inside Contexts. Translate all Subroutine values
// using the given translator.
//
VerificationEnv::VerificationEnv(const VerificationEnv &env, Function1<Subroutine, Subroutine> &translator):
common(env.common)
{
assert(env.live());
// Copy the bindings pointer (which is now only relevant to indicate whether this
// environment is live or not).
bindings = env.bindings;
sp = env.sp;
// Copy the context hierarchy.
activeContexts = 0;
Context *srcContext = env.activeContexts;
Context **dstContext = &activeContexts;
while (srcContext) {
*dstContext = new(common.envPool) Context(*srcContext, common, translator);
dstContext = &(*dstContext)->next;
srcContext = srcContext->next;
}
}
//
// Make this VerificationEnv (which must not have been initialized) live,
// assigning bkVoid to every slot.
//
void VerificationEnv::initLive()
{
assert(!live() && common.bindingPool);
// Create and initialize the bindings.
Binding *bdgs = new(*common.bindingPool) Binding[common.nEnvSlots];
bindings = bdgs;
Binding *bdgsEnd = bdgs + common.nEnvSlots;
while (bdgs != bdgsEnd)
bdgs++->setVoid();
sp = common.stackBase;
activeContexts = 0;
}
//
// Assign a copy of the given VerificationEnv (which must have been initialized)
// to this VerificationEnv, which is known to be uninitialized.
//
void VerificationEnv::copyEnv(const VerificationEnv &env)
{
assert(env.live() && common.bindingPool);
// Copy the bindings.
bindings = new(*common.bindingPool) Binding[common.nEnvSlots];
copy(env.bindings, env.bindings + common.nEnvSlots, bindings);
sp = env.sp;
// Copy the context hierarchy.
activeContexts = 0;
Context *srcContext = env.activeContexts;
Context **dstContext = &activeContexts;
while (srcContext) {
*dstContext = new(common.envPool) Context(*srcContext, common);
dstContext = &(*dstContext)->next;
srcContext = srcContext->next;
}
}
//
// Set the value of the given environment slot, adding that slot to
// the list of slots modified by all currently active subroutines.
//
void VerificationEnv::setSlot(Uint32 slot, const Binding &binding)
{
assert(slot < common.nEnvSlots);
bindings[slot] = binding;
for (Context *c = activeContexts; c; c = c->next)
c->modify(slot);
}
//
// Return the value of the one-word local variable in the given slot.
// Throw a verification error if the slot number is out of bounds or the value
// is undefined or a part of a two-word value.
//
const VerificationEnv::Binding &VerificationEnv::getLocal1(Uint32 n) const
{
assert(live() && common.bindingPool);
if (n >= common.nLocals)
verifyError(VerifyError::noSuchLocal);
Binding &b = bindings[n];
if (!b.isOneWord())
verifyError(VerifyError::badType);
return b;
}
//
// Return the value of the two-word local variable in the given slot.
// Throw a verification error if the slot number is out of bounds or the value
// is undefined or not a two-word value.
//
const VerificationEnv::Binding &VerificationEnv::getLocal2(Uint32 n) const
{
assert(live() && common.bindingPool);
if (n+1 >= common.nLocals)
verifyError(VerifyError::noSuchLocal);
Binding &b = bindings[n];
if (!b.isTwoWord())
verifyError(VerifyError::badType);
assert(bindings[n+1].hasKind(bkSecondWord));
return b;
}
//
// Set the value of the one-word local variable in the given slot.
// Throw a verification error if the slot number is out of bounds.
// The given binding must have a one-word kind.
//
void VerificationEnv::setLocal1(Uint32 n, const Binding &binding)
{
assert(live() && binding.isOneWord() && common.bindingPool);
if (n >= common.nLocals)
verifyError(VerifyError::noSuchLocal);
Binding *b = &bindings[n];
// If we're writing into an existing half of a doubleword,
// invalidate the other half of that doubleword.
BindingKind bk = b->getKind();
if (isTwoOrSecondWordKind(bk))
b[bk == bkSecondWord ? -1 : 1].setVoid();
setSlot(n, binding);
}
//
// Set the value of the two-word local variable in the given slot.
// Throw a verification error if the slot number is out of bounds.
// The given binding must have a two-word kind.
//
void VerificationEnv::setLocal2(Uint32 n, const Binding &binding)
{
assert(live() && binding.isTwoWord() && common.bindingPool);
if (n+1 >= common.nLocals)
verifyError(VerifyError::noSuchLocal);
Binding *b = &bindings[n];
// If we're writing into an existing half of a doubleword,
// invalidate the other half of that doubleword.
if (b[0].hasKind(bkSecondWord))
b[-1].setVoid();
if (b[1].isTwoWord())
b[2].setVoid();
setSlot(n, binding);
setSlot(n+1, secondWordBinding);
}
//
// Pop and return a one-word value from the stack.
// Throw a verification error if the stack underflows or the value
// is undefined or a part of a two-word value.
// Note that the returned reference will be invalidated by the next push.
//
const VerificationEnv::Binding &VerificationEnv::pop1()
{
assert(live() && common.bindingPool);
if (sp == common.stackBase)
verifyError(VerifyError::bytecodeStackUnderflow);
Binding &b = bindings[--sp];
if (!b.isOneWord())
verifyError(VerifyError::badType);
return b;
}
//
// Pop and return a one-word value from the stack.
// Throw a verification error if the stack underflows or the value
// is undefined or has a kind other than the given kind.
// Note that the returned reference will be invalidated by the next push.
//
const VerificationEnv::Binding &VerificationEnv::pop1(BindingKind bk)
{
assert(live() && isOneWordKind(bk) && common.bindingPool);
if (sp == common.stackBase)
verifyError(VerifyError::bytecodeStackUnderflow);
Binding &b = bindings[--sp];
if (!b.hasKind(bk))
verifyError(VerifyError::badType);
return b;
}
//
// Pop and return a two-word value or two one-word values from the stack.
// Throw a verification error if the stack underflows or the value
// is undefined or a part of a two-word value that includes one of the two
// stack slots but not the other.
//
void VerificationEnv::pop2(Binding &binding1, Binding &binding2)
{
assert(live() && common.bindingPool);
if (sp <= common.stackBase+1)
verifyError(VerifyError::bytecodeStackUnderflow);
sp -= 2;
Binding *b = &bindings[sp];
BindingKind bk1 = b[0].getKind();
BindingKind bk2 = b[1].getKind();
if (!(isOneWordKind(bk1) && isOneWordKind(bk2) || isTwoWordKind(bk1)))
verifyError(VerifyError::badType);
assert(!isTwoWordKind(bk1) || bk2 == bkSecondWord);
binding1 = b[0];
binding2 = b[1];
}
//
// Pop and return a two-word value from the stack.
// Throw a verification error if the stack underflows or the value
// is undefined or has a kind other than the given kind.
// Note that the returned reference will be invalidated by the next push.
//
const VerificationEnv::Binding &VerificationEnv::pop2(BindingKind bk)
{
assert(live() && isTwoWordKind(bk) && common.bindingPool);
if (sp <= common.stackBase+1)
verifyError(VerifyError::bytecodeStackUnderflow);
sp -= 2;
Binding *b = &bindings[sp];
if (!b[0].hasKind(bk))
verifyError(VerifyError::badType);
assert(b[1].hasKind(bkSecondWord));
return *b;
}
//
// Pop and return a one or two-word value from the stack, depending on bk.
// Throw a verification error if the stack underflows or the value
// is undefined or has a kind other than the given kind.
// Note that the returned reference will be invalidated by the next push.
//
const VerificationEnv::Binding &VerificationEnv::pop1or2(BindingKind bk)
{
return isTwoWordKind(bk) ? pop2(bk) : pop1(bk);
}
//
// Push a one-word value onto the stack.
// Throw a verification error if the stack overflows.
// The given binding must have a one-word kind.
//
void VerificationEnv::push1(const Binding &binding)
{
assert(live() && binding.isOneWord() && common.bindingPool);
if (sp == common.nEnvSlots)
verifyError(VerifyError::bytecodeStackOverflow);
setSlot(sp++, binding);
}
//
// Push a one-word value that contains a new binding of the given kind onto the stack.
// Throw a verification error if the stack overflows.
//
void VerificationEnv::push1(BindingKind bk)
{
// Note: bkAddr will be outlawed here once we start to distinguish among types of
// pointers.
assert(bk == bkVoid || bk == bkInt || bk == bkFloat || bk == bkAddr);
InitBinding b(bk);
push1(b);
}
//
// Push a two-word value onto the stack.
// Throw a verification error if the stack overflows.
// The given binding must have a two-word kind.
//
void VerificationEnv::push2(const Binding &binding)
{
assert(live() && binding.isTwoWord() && common.bindingPool);
if (sp+1 >= common.nEnvSlots)
verifyError(VerifyError::bytecodeStackOverflow);
setSlot(sp++, binding);
setSlot(sp++, secondWordBinding);
}
//
// Push a two-word value that contains a new binding of the given kind onto the stack.
// Throw a verification error if the stack overflows.
//
void VerificationEnv::push2(BindingKind bk)
{
assert(bk == bkLong || bk == bkDouble);
InitBinding b(bk);
push2(b);
}
//
// Push a two-word value or two one-word values onto the stack.
// Throw a verification error if the stack overflows.
// The given bindings must be the two words of a two-word value
// or both be one-word values.
//
void VerificationEnv::push2(const Binding &binding1, const Binding &binding2)
{
assert(live() && (binding1.isTwoWord() && binding2.hasKind(bkSecondWord) ||
binding1.isOneWord() && binding2.isOneWord())
&& common.bindingPool);
if (sp+1 >= common.nEnvSlots)
verifyError(VerifyError::bytecodeStackOverflow);
setSlot(sp++, binding1);
setSlot(sp++, binding2);
}
//
// Push a one or two-word value that contains a new binding of the
// given kind onto the stack.
// Throw a verification error if the stack overflows.
//
void VerificationEnv::push1or2(BindingKind bk)
{
// Note: bkAddr will be outlawed here once we start to distinguish among types of
// pointers.
assert(bk == bkVoid || bk == bkInt || bk == bkFloat || bk == bkAddr || bk == bkLong || bk == bkDouble);
InitBinding b(bk);
if (isTwoWordKind(bk))
push2(b);
else
push1(b);
}
//
// Push the context of the given subroutine onto the list of currently active
// contexts. Initialize that context to record all bindings written to this
// environment after this enterSubroutine call.
//
// Throw a verification error if the given subroutine already is on the list
// of active contexts. This rejects bytecode programs that call subroutines
// recursively. It also rejects some "valid" bytecode programs that do not call
// subroutines recursively (for instance, if subroutine A exits via a jump
// instead of a ret and then calls subroutine A again), but, fortunately, the
// current definition of the Java language does not generate such programs.
// (Specifically, each Java try block has a single entry point and the finally
// handler -- say, subroutine A -- for that try block is outside that block. In
// order for subroutine A to be called again, execution must proceed again
// through the entry point of the try block, and we know that at that point
// subroutine A is not one of the active contexts.)
//
void VerificationEnv::enterSubroutine(Subroutine s)
{
assert(live() && s && common.bindingPool);
if (Context::find(activeContexts, s))
verifyError(VerifyError::jsrNestingError);
Context *c = new(common.envPool) Context(s, common);
c->next = activeContexts;
activeContexts = c;
}
//
// Pop the context of the given subroutine from the list of currently active
// contexts, and replace environment bindings that were not modified by the
// subroutine by their contenst from entryEnv, which represents the environment
// as it was just before entry to the subroutine. Also pop any contexts more
// recent than that of the given subroutine -- these subroutines apparently
// exited using a jump instead of a ret.
//
// Throw a verification error if the subroutine is not on the list of active
// contexts, which indicates that there is some program path along which this
// ret could be reached without this subroutine having been called first.
//
void VerificationEnv::exitSubroutine(Subroutine s, const VerificationEnv &entryEnv)
{
assert(live() && s && entryEnv.live() && common.bindingPool);
Context *c = Context::find(activeContexts, s);
if (!c)
verifyError(VerifyError::jsrNestingError);
activeContexts = c->next;
// Replace unmodified environment bindings.
Uint32 nSlots = sp;
const Binding *srcBindings = entryEnv.bindings;
Binding *dstBindings = bindings;
for (Uint32 slot = 0; slot != nSlots; slot++)
if (!c->isModified(slot))
dstBindings[slot] = srcBindings[slot];
}
//
// Intersect the given VerificationEnv (which must be live) into this
// VerificationEnv, which must also be live. The two environments may have
// different sets of active subroutine contexts, in which case leave the maximal
// common set (for instance, intersecting a->b with b yields b, while
// intersecting a->b->d->e with a->c->d yields a->d). Because each subroutine has
// only one entry point and cannot be recursive, we don't have to worry about
// cases such as intersecting a->b with b->a -- nesting of subroutines follows a
// partial order.
//
// Return true if this VerificationEnv changed.
//
// Throw a verification error if the environments have different stack depths.
//
bool VerificationEnv::meet(const VerificationEnv &env)
{
assert(live() && env.live() && common.bindingPool);
Uint32 nSlots = sp;
if (nSlots != env.sp)
verifyError(VerifyError::bytecodeStackDynamic);
bool changed = false;
// Merge context lists
Context **dstContextPtr = &activeContexts;
Context *srcContext = env.activeContexts;
Context *dstContext;
while ((dstContext = *dstContextPtr) != 0) {
Context *c = Context::find(srcContext, dstContext->subroutine);
if (c) {
srcContext = c;
changed |= dstContext->meet(*c, nSlots);
dstContextPtr = &dstContext->next;
} else {
// Remove this destination context.
*dstContextPtr = dstContext->next;
changed = true;
}
}
// Merge bindings
const Binding *srcBinding = env.bindings;
Binding *dstBinding = bindings;
Binding *dstBindingsEnd = dstBinding + nSlots;
while (dstBinding != dstBindingsEnd) {
if (*dstBinding != *srcBinding && !dstBinding->hasKind(bkVoid)) {
dstBinding->setVoid();
changed = true;
}
srcBinding++;
dstBinding++;
}
return changed;
}
//
// This VerificationEnv (which must be live) is the entry environment to a ret
// bytecode that returns from subroutine s. That subroutine's context is one
// of the active contexts in this VerificationEnv. Set that context's retReachable
// flag because clearly subroutine s's ret is reachable from here.
//
void VerificationEnv::setRetReachable(Subroutine s)
{
assert(live());
Context *c = Context::find(activeContexts, s);
assert(c);
c->retReachable = true;
}
//
// Merge the retReachable flags of env into this VerificationEnv. env is the
// environment of a successor of this VerificationEnv's block. If s is non-nil,
// this VerificationEnv's block is a jsr instruction that calls subroutine s,
// and env belongs to s's first block; in this case don't set this environment's
// retReachable flag for s's context because this environment is outside s.
//
// Return true if this VerificationEnv changed.
//
bool VerificationEnv::mergeRetReachables(const VerificationEnv &env, Subroutine s)
{
assert(live() && env.live());
bool changed = false;
Context *srcContext = env.activeContexts;
Context *dstContext = activeContexts;
while (srcContext) {
if (srcContext->retReachable) {
Subroutine srcSubroutine = srcContext->subroutine;
if (srcSubroutine != s) {
dstContext = Context::find(dstContext, srcSubroutine);
assert(dstContext);
if (!dstContext->retReachable) {
dstContext->retReachable = true;
changed = true;
}
}
}
srcContext = srcContext->next;
}
return changed;
}

Просмотреть файл

@ -0,0 +1,210 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef VERIFICATIONENV_H
#define VERIFICATIONENV_H
#include "LocalEnv.h"
#include "Value.h"
#include "ErrorHandling.h"
struct BytecodeBlock;
class VerificationEnv
{
public:
typedef BytecodeBlock *Subroutine; // A subroutine is represented by a pointer to its entry BytecodeBlock
enum BindingKind
{
bkVoid, // Undefined stack word
bkReturn, // jsr/ret return value
bkInt, // int value
bkFloat, // float value
bkAddr, // Object pointer value
bkLong, // First word of a long value
bkDouble, // First word of a double value
bkSecondWord // Second word of a long or double value
};
private:
static const BindingKind valueKindBindingKinds[nValueKinds];
static const BindingKind typeKindBindingKinds[nTypeKinds];
public:
static bool isOneWordKind(BindingKind kind) {return (uint)(kind - bkReturn) <= (uint)(bkAddr - bkReturn);}
static bool isTwoWordKind(BindingKind kind) {return (uint)(kind - bkLong) <= (uint)(bkDouble - bkLong);}
static bool isTwoOrSecondWordKind(BindingKind kind) {return (uint)(kind - bkLong) <= (uint)(bkSecondWord - bkLong);}
static BindingKind valueKindToBindingKind(ValueKind kind) {return valueKindBindingKinds[kind];}
static BindingKind typeKindToBindingKind(TypeKind kind) {return typeKindBindingKinds[kind];}
class Binding
{
BindingKind kind; // Kind of value held in this stack slot
union {
Subroutine subroutine; // If kind is bkReturn, the subroutine that was called
};
public:
BindingKind getKind() {return kind;}
bool hasKind(BindingKind k) const {return kind == k;}
bool isOneWord() const {return isOneWordKind(kind);}
bool isTwoWord() const {return isTwoWordKind(kind);}
bool isTwoOrSecondWord() const {return isTwoOrSecondWordKind(kind);}
bool operator==(const Binding &b2) const {return kind == b2.kind && (kind != bkReturn || subroutine == b2.subroutine);}
bool operator!=(const Binding &b2) const {return !operator==(b2);}
void setVoid() {kind = bkVoid;}
void setReturn(Subroutine s) {kind = bkReturn; subroutine = s;}
void setKind(BindingKind k) {assert(k != bkReturn); kind = k;}
Subroutine getSubroutine() const {assert(kind == bkReturn); return subroutine;}
};
struct InitBinding: Binding
{
explicit InitBinding(BindingKind kind) {setKind(kind);}
};
struct Common: CommonEnv
{
Pool *bindingPool; // Pool used for allocating arrays of bindings and 'modified' arrays inside Contexts; nil if none
Common(Pool &envPool, Pool *bindingPool, Uint32 nLocals, Uint32 stackSize):
CommonEnv(envPool, 0, nLocals, stackSize), bindingPool(bindingPool) {}
void setBindingPool(Pool &pool) {assert(!bindingPool); bindingPool = &pool;}
void clearBindingPool() {bindingPool = 0;} // Trashes bindings arrays and 'modified' arrays inside Contexts
};
private:
struct Context
{
Context *next; // Link to next outer subroutine context or nil if none
const Subroutine subroutine; // Pointer to the first instruction of a subroutine that was called and not yet returned
private:
char *modified; // Array of nLocals+stackSize bytes; each is set if the corresponding local variable
// or stack temporary has been modified since entry to the subroutine;
public: // undefined if common.bindingPool is nil.
bool retReachable; // True if subroutine's ret is reachable from this block (without going through subroutine's jsr)
#ifdef DEBUG
const Common &common; // Backpointer to information shared among all VerificationEnvs in a graph
#endif
Context(Subroutine subroutine, const Common &common);
Context(const Context &src, const Common &common);
Context(const Context &src, const Common &common, Function1<Subroutine, Subroutine> &translator);
void modify(Uint32 slot) {assert(common.bindingPool); modified[slot] = 1;}
bool isModified(Uint32 slot) {assert(common.bindingPool); return modified[slot] != 0;}
bool meet(const Context &src, Uint32 nSlots);
static Context *find(Context *list, const Subroutine subroutine);
};
Common &common; // Backpointer to information shared among all VerificationEnvs in a graph
Binding *bindings; // Array of:
// nLocals local variable bindings
// stackSize stack temporaries' bindings;
// bindings==nil means no information is available yet.
// If common.bindingPool is nil, bindings is either nil or non-nil but does not point to anything.
Uint32 sp; // Stack pointer (index within bindings array of first unused temporary)
// Bindings at indices 0..sp-1 are valid; others are ignored
Context *activeContexts; // Linked list of all currently active subroutines from inner to outer
static const InitBinding secondWordBinding; // Always contains a bkSecondWord binding
public:
explicit VerificationEnv(Common &common): common(common), bindings(0) {}
VerificationEnv(const VerificationEnv &env): common(env.common) {copyEnv(env);}
VerificationEnv(const VerificationEnv &env, Function1<Subroutine, Subroutine> &translator);
void operator=(const VerificationEnv &env) {assert(!live()); copyEnv(env);}
void move(VerificationEnv &env);
void initLive();
bool live() const {return bindings != 0;}
private:
void copyEnv(const VerificationEnv &env);
void setSlot(Uint32 slot, const Binding &binding);
public:
// Local variable operations
const Binding &getLocal1(Uint32 n) const;
const Binding &getLocal2(Uint32 n) const;
void setLocal1(Uint32 n, const Binding &binding);
void setLocal2(Uint32 n, const Binding &binding);
// Stack operations
Uint32 getSP() const {return sp - common.stackBase;}
void dropAll() {sp = common.stackBase;}
const Binding &pop1();
const Binding &pop1(BindingKind bk);
void pop2(Binding &binding1, Binding &binding2);
const Binding &pop2(BindingKind bk);
const Binding &pop1or2(BindingKind bk);
void push1(const Binding &binding);
void push1(BindingKind bk);
void push2(const Binding &binding);
void push2(BindingKind bk);
void push2(const Binding &binding1, const Binding &binding2);
void push1or2(BindingKind bk);
void enterSubroutine(Subroutine s);
void exitSubroutine(Subroutine s, const VerificationEnv &entryEnv);
bool meet(const VerificationEnv &env);
bool isRetReachable(Subroutine s);
void setRetReachable(Subroutine s);
bool mergeRetReachables(const VerificationEnv &env, Subroutine s);
};
// --- INLINES ----------------------------------------------------------------
//
// Destructively move the given VerificationEnv (which must have been initialized)
// to this VerificationEnv, which must be uninitialized. The given VerificationEnv is
// left uninitialized.
//
inline void VerificationEnv::move(VerificationEnv &env)
{
assert(!live() && env.live());
bindings = env.bindings;
sp = env.sp;
activeContexts = env.activeContexts;
#ifdef DEBUG
env.bindings = 0;
env.activeContexts = 0;
#endif
}
//
// Return true if Subroutine s is one of the active contexts in this VerificationEnv
// and that context's retReachable flag is true.
//
inline bool VerificationEnv::isRetReachable(Subroutine s)
{
assert(live());
Context *c = Context::find(activeContexts, s);
return c && c->retReachable;
}
#endif

56
ef/Compiler/Makefile Normal file
Просмотреть файл

@ -0,0 +1,56 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#######################################################################
# (1) Directory specific info #
#######################################################################
DEPTH = ..
DIRS = CodeGenerator FrontEnd PrimitiveGraph Optimizer RegisterAllocator
SUBMODULES = $(DIRS)
MODULE_NAME = EF
NO_PROGRAM_IN_SUBDIRS = 1
NO_INSTALL_IN_SUBDIRS = 1
#######################################################################
# (2) Include "component" configuration information. #
#######################################################################
include $(DEPTH)/config/config.mk
#######################################################################
# (3) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
#######################################################################
# (4) Execute "component" rules. (OPTIONAL) #
#######################################################################
include $(DEPTH)/config/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше