mirror of https://git.wuffs.org/MWCC
239 lines
6.8 KiB
C
239 lines
6.8 KiB
C
#ifndef COMPILER_PCODE_H
|
|
#define COMPILER_PCODE_H
|
|
|
|
#include "compiler/common.h"
|
|
#include "compiler/PCodeInfo.h"
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma options align=mac68k
|
|
#endif
|
|
|
|
#define FLAG_SET_T(flags) (((flags) & (fIsBranch | fIsCall)) ? (flags) : 0)
|
|
#define FLAG_SET_F(flags) (((flags) & (fIsBranch | fIsCall)) ? 0 : (flags))
|
|
|
|
#define PCODE_FLAG_SET_T(pcode) ((((PCode *) (pcode))->flags & (fIsBranch | fIsCall)) ? ((PCode *) (pcode))->flags : 0)
|
|
#define PCODE_FLAG_SET_F(pcode) ((((PCode *) (pcode))->flags & (fIsBranch | fIsCall)) ? 0 : ((PCode *) (pcode))->flags)
|
|
|
|
enum {
|
|
EffectRead = 1,
|
|
EffectWrite = 2,
|
|
Effect4 = 4,
|
|
Effect8 = 8,
|
|
Effect40 = 0x40 // spilled register?
|
|
};
|
|
|
|
typedef enum {
|
|
RefType_0,
|
|
RefType_1, // like D, but 32-bit?
|
|
RefType_2, // matches MW_RELOC_3?
|
|
RefType_3, // matches MW_RELOC_4?
|
|
RefType_4,
|
|
RefType_5,
|
|
RefType_6, // LO16?
|
|
RefType_7, // HI16?
|
|
RefType_8, // HA16?
|
|
RefType_9,
|
|
RefType_A, // another LO
|
|
RefType_B, // another HA
|
|
RefType_C, // another HA
|
|
RefType_D // another LO
|
|
} PCRefType;
|
|
|
|
struct PCodeArg {
|
|
PCOpKind kind;
|
|
RegClass arg;
|
|
union {
|
|
struct {
|
|
unsigned short effect;
|
|
short reg;
|
|
} reg;
|
|
struct {
|
|
SInt32 value;
|
|
Object *obj;
|
|
} imm;
|
|
struct {
|
|
SInt32 offset;
|
|
Object *obj;
|
|
} mem;
|
|
struct {
|
|
PCodeLabel *label;
|
|
} label;
|
|
struct {
|
|
SInt16 offset;
|
|
PCodeLabel *labelA;
|
|
PCodeLabel *labelB;
|
|
} labeldiff;
|
|
unsigned char placeholder[10]; // keep the size
|
|
} data;
|
|
};
|
|
|
|
#define PC_OP_IS_REGISTER(_op, _rclass, _reg) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass) && \
|
|
(_op)->data.reg.reg == (_reg))
|
|
|
|
#define PC_OP_IS_READ_REGISTER(_op, _rclass, _reg) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass) && \
|
|
(_op)->data.reg.reg == (_reg) && \
|
|
((_op)->data.reg.effect & EffectRead))
|
|
|
|
#define PC_OP_IS_WRITE_REGISTER(_op, _rclass, _reg) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass) && \
|
|
(_op)->data.reg.reg == (_reg) && \
|
|
((_op)->data.reg.effect & EffectWrite))
|
|
|
|
#define PC_OP_IS_R_OR_W_REGISTER(_op, _rclass, _reg) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass) && \
|
|
(_op)->data.reg.reg == (_reg) && \
|
|
((_op)->data.reg.effect & (EffectRead | EffectWrite)))
|
|
|
|
#define PC_OP_IS_ANY_REGISTER(_op, _rclass) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass))
|
|
|
|
#define PC_OP_IS_READ_ANY_REGISTER(_op, _rclass) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass) && \
|
|
((_op)->data.reg.effect & EffectRead))
|
|
|
|
#define PC_OP_IS_WRITE_ANY_REGISTER(_op, _rclass) \
|
|
((_op)->kind == PCOp_REGISTER && \
|
|
(_op)->arg == (_rclass) && \
|
|
((_op)->data.reg.effect & EffectWrite))
|
|
|
|
|
|
struct PCode {
|
|
PCode *nextPCode;
|
|
PCode *prevPCode;
|
|
PCodeBlock *block;
|
|
int useID;
|
|
int defID;
|
|
UInt32 flags;
|
|
struct Alias *alias;
|
|
SInt32 sourceoffset;
|
|
short op;
|
|
short argCount;
|
|
PCodeArg args[0];
|
|
};
|
|
|
|
struct PCodeLabel {
|
|
PCodeLabel *nextLabel;
|
|
PCodeBlock *block;
|
|
short resolved;
|
|
unsigned short index;
|
|
};
|
|
|
|
typedef struct _PCLink {
|
|
struct _PCLink *nextLink;
|
|
struct PCodeBlock *block;
|
|
} PCLink;
|
|
|
|
struct PCodeBlock {
|
|
struct PCodeBlock *nextBlock;
|
|
struct PCodeBlock *prevBlock;
|
|
PCodeLabel *labels;
|
|
PCLink *predecessors;
|
|
PCLink *successors;
|
|
PCode *firstPCode;
|
|
PCode *lastPCode;
|
|
int blockIndex;
|
|
int codeOffset; // in bytes
|
|
int loopWeight;
|
|
short pcodeCount;
|
|
unsigned short flags;
|
|
};
|
|
|
|
/* PCode Flags */
|
|
enum {
|
|
fIsBranch = 1,
|
|
fIsRead = 2, // read from memory
|
|
fIsWrite = 4, // write to memory
|
|
fIsCall = 8,
|
|
fIsMove = 0x10, // moves register (mcrf, mr, fmr, vmr, vmrp)
|
|
// Always valid
|
|
fIsConst = 0x40,
|
|
fIsVolatile = 0x80,
|
|
fSideEffects = 0x100, // instructions that do weird stuff with PPC state
|
|
fPCodeFlag200 = 0x200, // ?
|
|
fPCodeFlag400 = 0x400, // ?
|
|
fPCodeFlag800 = 0x800, // ?
|
|
fPCodeFlag1000 = 0x1000, // ?
|
|
fCommutative = 0x2000,
|
|
fIsCSE = 0x4000,
|
|
fIsArgInit = 0x8000, // instruction that stores varargs from GPRs to the stack
|
|
fPCodeFlag20000 = 0x20000, // some kinda load?
|
|
fPCodeFlag40000 = 0x40000, // some kinda store?
|
|
// Set 1 (branches) only
|
|
fLink = 0x1000000,
|
|
fCanLink = 0x2000000, // is capable of being a link branch
|
|
fBranchNotTaken = 0x4000000,
|
|
fBranchTaken = 0x8000000,
|
|
fAbsolute = 0x10000000,
|
|
fCanBeAbsolute = 0x20000000, // is capable of having fAbsolute set
|
|
// Set 2 (non-branches) only
|
|
fIsPtrOp = 0x20,
|
|
fPCodeFlag200000 = 0x200000,
|
|
fPCodeFlag400000 = 0x400000,
|
|
fOverflow = 0x800000,
|
|
fUpdatesPtr = 0x2000000, // lbzu, lbzux, lwzu, stbu, stbux, etc
|
|
fCanSetCarry = 0x4000000, // is capable of having fSetsCarry set
|
|
fCanSetRecordBit = 0x8000000, // is capable of having fRecordBit set
|
|
fSetsCarry = 0x10000000,
|
|
fRecordBit = 0x20000000,
|
|
fOpTypeFPR = 0x40000000,
|
|
fOpTypeGPR = 0x80000000,
|
|
fOpTypeVR = 0xC0000000,
|
|
fOpTypeMask = 0xC0000000
|
|
};
|
|
|
|
enum {
|
|
fIsProlog = 1, // fIsProlog
|
|
fIsEpilogue = 2, // fIsEpilogue
|
|
fVisited = 4, // fVisited
|
|
fScheduled = 8, // fScheduled
|
|
fPCBlockFlag10 = 0x10, // maybe fIsSwitch based off v3?
|
|
fDeleted = 0x20,
|
|
fPCBlockFlag2000 = 0x2000,
|
|
fPCBlockFlag4000 = 0x4000,
|
|
fPCBlockFlag6000 = 0x6000,
|
|
fPCBlockFlag8000 = 0x8000
|
|
};
|
|
// v3 has fCCisLiveOnExit, fUnrolled, fAlignBlock
|
|
|
|
extern PCodeBlock *pcbasicblocks;
|
|
extern PCodeBlock *pclastblock;
|
|
extern PCodeBlock *prologue;
|
|
extern PCodeBlock *epilogue;
|
|
extern PCodeBlock **depthfirstordering;
|
|
extern int pcblockcount;
|
|
extern int pcloopweight;
|
|
|
|
extern void initpcode(void);
|
|
extern PCode *makepcode(Opcode op, ...);
|
|
extern void emitpcode(Opcode op, ...);
|
|
extern PCode *copypcode(PCode *pcode);
|
|
extern PCodeLabel *makepclabel(void);
|
|
extern PCodeBlock *makepcblock(void);
|
|
extern void pclabel(PCodeBlock *block, PCodeLabel *label);
|
|
extern void pcbranch(PCodeBlock *block, PCodeLabel *label);
|
|
extern void pccomputepredecessors(void);
|
|
extern void deleteblock(PCodeBlock *block);
|
|
extern void deleteunreachableblocks(void);
|
|
extern void appendpcode(PCodeBlock *block, PCode *pcode);
|
|
extern void deletepcode(PCode *pcode);
|
|
extern void insertpcodebefore(PCode *anchor, PCode *newpcode);
|
|
extern void insertpcodeafter(PCode *anchor, PCode *newpcode);
|
|
extern void setpcodeflags(int flags);
|
|
extern void clearpcodeflags(int flags);
|
|
extern int pccomputeoffsets(void);
|
|
extern void computedepthfirstordering(void);
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
#endif
|