mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 18:27:35 +00:00
281 lines
9.2 KiB
C++
281 lines
9.2 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
//
|
|
// 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 ~InsnExternalUse() {}
|
|
|
|
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 ~InsnExternalDefine() {}
|
|
|
|
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
|