gecko-dev/ef/Compiler/CodeGenerator/Instruction.h
1999-11-02 06:38:29 +00:00

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