#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)->flags & (fIsBranch | fIsCall)) ? (pcode)->flags : 0) #define PCODE_FLAG_SET_F(pcode) (((pcode)->flags & (fIsBranch | fIsCall)) ? 0 : (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