Files
ppsspp/Core/MIPS/IR/IRInst.h

413 lines
7.7 KiB
C
Raw Permalink Normal View History

2016-05-06 23:45:37 +02:00
#pragma once
#include <cstdint>
2016-05-06 23:45:37 +02:00
#include <vector>
2016-05-13 19:31:27 +02:00
#include <utility>
2016-05-06 23:45:37 +02:00
#include "Common/CommonTypes.h"
#include "Core/MIPS/MIPS.h"
// Basic IR
//
// This IR refers implicitly to the MIPS register set and is simple to interpret.
// To do real compiler things with it and do full-function compilation, it probably
// needs to be lifted to a higher IR first, before being lowered onto each target.
// But this gets rid of a lot of MIPS idiosyncrasies that makes it tricky, like
// delay slots, and is very suitable for translation into other IRs. Can of course
// even be directly JIT-ed, but the gains will probably be tiny over our older direct
// MIPS->target JITs.
enum class IROp : uint8_t {
Nop,
2016-05-06 23:45:37 +02:00
SetConst,
2016-05-08 13:32:22 +02:00
SetConstF,
2016-05-06 23:45:37 +02:00
Mov,
Add,
Sub,
Neg,
Not,
And,
Or,
Xor,
AddConst,
SubConst,
AndConst,
OrConst,
XorConst,
Shl,
Shr,
Sar,
Ror,
// The shift is stored directly, not in the const table, so Imm instead of Const
ShlImm,
ShrImm,
SarImm,
RorImm,
2016-05-06 23:45:37 +02:00
Slt,
SltConst,
SltU,
SltUConst,
Clz,
// Conditional moves
MovZ,
MovNZ,
Max,
Min,
// Byte swaps. All CPUs have native ones so worth keeping.
BSwap16, // Swaps both the high and low byte pairs.
BSwap32,
// Weird Hi/Lo semantics preserved. Too annoying to do something more generic.
MtLo,
MtHi,
MfLo,
MfHi,
Mult,
MultU,
2016-05-06 23:45:37 +02:00
Madd,
MaddU,
Msub,
MsubU,
Div,
DivU,
2016-05-06 23:45:37 +02:00
// These take a constant from the pool as an offset.
// Loads from a constant address can be represented by using r0.
Load8,
Load8Ext,
Load16,
Load16Ext,
Load32,
Load32Left,
Load32Right,
Load32Linked,
2016-05-06 23:45:37 +02:00
LoadFloat,
2016-05-09 23:47:56 +02:00
LoadVec4,
2016-05-06 23:45:37 +02:00
Store8,
Store16,
Store32,
Store32Left,
Store32Right,
Store32Conditional,
2016-05-06 23:45:37 +02:00
StoreFloat,
2016-05-09 23:47:56 +02:00
StoreVec4,
2016-05-06 23:45:37 +02:00
Ext8to32,
Ext16to32,
ReverseBits,
2016-05-06 23:45:37 +02:00
FAdd,
FSub,
FMul,
FDiv,
FMin,
FMax,
2016-05-06 23:45:37 +02:00
FMov,
FSqrt,
FNeg,
FAbs,
2016-05-15 10:34:30 +02:00
FSign,
2016-05-06 23:45:37 +02:00
FRound,
FTrunc,
FCeil,
FFloor,
FCvtWS,
FCvtSW,
FCvtScaledWS,
FCvtScaledSW,
2016-05-06 23:45:37 +02:00
FMovFromGPR,
FMovToGPR,
2016-05-10 23:14:26 +02:00
FSat0_1,
FSatMinus1_1,
FpCondFromReg,
2016-05-06 23:45:37 +02:00
FpCondToReg,
FpCtrlFromReg,
FpCtrlToReg,
VfpuCtrlToReg,
2016-05-06 23:45:37 +02:00
FCmp,
FCmovVfpuCC,
2016-05-12 22:35:31 +02:00
FCmpVfpuBit,
FCmpVfpuAggregate,
2016-05-06 23:45:37 +02:00
// Rounding Mode
RestoreRoundingMode,
ApplyRoundingMode,
UpdateRoundingMode,
SetCtrlVFPU,
SetCtrlVFPUReg,
SetCtrlVFPUFReg,
2016-05-06 23:45:37 +02:00
2016-05-11 00:16:07 +02:00
// 4-wide instructions to assist SIMD.
// Can of course add a pass to break them up if a target does not
// support SIMD.
Vec4Init,
Vec4Shuffle,
Vec4Blend,
Vec4Mov,
Vec4Add,
Vec4Sub,
Vec4Mul,
Vec4Div,
Vec4Scale,
Vec4Dot,
2016-05-13 20:15:20 +02:00
Vec4Neg,
Vec4Abs,
2016-05-10 21:50:08 +02:00
2016-05-12 22:35:31 +02:00
// vx2i
2016-05-15 10:34:30 +02:00
Vec2Unpack16To31, // Note that the result is shifted down by 1, hence 31
Vec2Unpack16To32,
Vec4Unpack8To32,
Vec4DuplicateUpperBitsAndShift1, // Bizarro vuc2i behaviour, in an instruction. Split?
2016-05-15 11:45:34 +02:00
Vec4ClampToZero,
Vec2ClampToZero,
Vec4Pack31To8,
Vec4Pack32To8,
Vec2Pack31To16,
Vec2Pack32To16,
2016-05-12 22:35:31 +02:00
2016-05-10 21:50:08 +02:00
// Slow special functions. Used on singles.
FSin,
FCos,
FRSqrt,
FRecip,
FAsin,
2016-05-10 21:50:08 +02:00
2016-05-06 23:45:37 +02:00
// Fake/System instructions
Interpret,
// Emit this before you exit. Semantic is to set the downcount
2016-05-06 23:45:37 +02:00
// that will be used at the actual exit.
Downcount, // src1 + (src2<<8)
// End-of-basic-block.
ExitToConst, // 0, const, downcount
ExitToReg,
ExitToConstIfEq, // const, reg1, reg2
ExitToConstIfNeq, // const, reg1, reg2
ExitToConstIfGtZ, // const, reg1, 0
ExitToConstIfGeZ, // const, reg1, 0
ExitToConstIfLtZ, // const, reg1, 0
ExitToConstIfLeZ, // const, reg1, 0
ExitToConstIfFpTrue,
ExitToConstIfFpFalse,
ExitToPC, // Used after a syscall to give us a way to do things before returning.
2016-05-06 23:45:37 +02:00
Syscall,
SetPC, // hack to make syscall returns work
SetPCConst, // hack to make replacement know PC
CallReplacement,
2016-05-06 23:45:37 +02:00
Break,
// Debugging breakpoints.
Breakpoint,
MemoryCheck,
ValidateAddress8,
ValidateAddress16,
ValidateAddress32,
ValidateAddress128,
2016-05-06 23:45:37 +02:00
};
enum IRComparison {
Greater,
GreaterEqual,
Less,
LessEqual,
Equal,
NotEqual,
Bad,
};
2016-05-10 21:50:08 +02:00
// Some common vec4 constants.
enum class Vec4Init {
AllZERO,
AllONE,
AllMinusONE,
Set_1000,
Set_0100,
Set_0010,
Set_0001,
};
2023-09-01 22:29:24 -07:00
enum class IRRoundMode : uint8_t {
RINT_0 = 0,
CAST_1 = 1,
CEIL_2 = 2,
FLOOR_3 = 3,
};
2016-05-06 23:45:37 +02:00
// Hm, unused
inline IRComparison Invert(IRComparison comp) {
switch (comp) {
case IRComparison::Equal: return IRComparison::NotEqual;
case IRComparison::NotEqual: return IRComparison::Equal;
case IRComparison::Greater: return IRComparison::LessEqual;
case IRComparison::GreaterEqual: return IRComparison::Less;
case IRComparison::Less: return IRComparison::GreaterEqual;
case IRComparison::LessEqual: return IRComparison::Greater;
default:
return IRComparison::Bad;
}
}
inline IROp ComparisonToExit(IRComparison comp) {
switch (comp) {
case IRComparison::Equal: return IROp::ExitToConstIfEq;
case IRComparison::NotEqual: return IROp::ExitToConstIfNeq;
case IRComparison::Greater: return IROp::ExitToConstIfGtZ;
case IRComparison::GreaterEqual: return IROp::ExitToConstIfGeZ;
case IRComparison::Less: return IROp::ExitToConstIfLtZ;
case IRComparison::LessEqual: return IROp::ExitToConstIfLeZ;
default:
return IROp::Break;
}
}
enum IRFpCompareMode {
False = 0,
EitherUnordered,
EqualOrdered, // eq, seq (equal, ordered)
EqualUnordered, // ueq, ngl (equal, unordered)
LessOrdered, // olt, lt (less than, ordered)
LessUnordered, // ult, nge (less than, unordered)
LessEqualOrdered, // ole, le (less equal, ordered)
LessEqualUnordered, // ule, ngt (less equal, unordered)
};
2023-07-20 19:21:00 -07:00
typedef u8 IRReg;
enum : IRReg {
2016-05-06 23:45:37 +02:00
IRTEMP_0 = 192,
IRTEMP_1,
IRTEMP_2,
IRTEMP_3,
IRTEMP_LHS, // Reserved for use in branches
IRTEMP_RHS, // Reserved for use in branches
IRTEMP_LR_ADDR, // Reserved for left/right loads and stores.
IRTEMP_LR_VALUE, // Reserved for left/right loads and stores.
IRTEMP_LR_MASK, // Reserved for left/right loads and stores.
IRTEMP_LR_SHIFT, // Reserved for left/right loads and stores.
2016-05-06 23:45:37 +02:00
2016-05-11 00:16:07 +02:00
IRVTEMP_PFX_S = 224 - 32, // Relative to the FP regs
IRVTEMP_PFX_T = 228 - 32,
IRVTEMP_PFX_D = 232 - 32,
IRVTEMP_0 = 236 - 32,
2016-05-06 23:45:37 +02:00
// Hacky way to get to other state
2016-05-09 23:47:56 +02:00
IRREG_VFPU_CTRL_BASE = 208,
IRREG_VFPU_CC = 211,
2016-05-11 00:16:07 +02:00
IRREG_LO = 242, // offset of lo in MIPSState / 4
IRREG_HI = 243,
IRREG_FCR31 = 244,
IRREG_FPCOND = 245,
2023-07-29 17:53:15 -07:00
IRREG_LLBIT = 250,
2016-05-06 23:45:37 +02:00
};
enum IRFlags {
// Uses src3, not dest.
IRFLAG_SRC3 = 0x0001,
// Uses src3 AND dest (i.e. mutates dest.)
IRFLAG_SRC3DST = 0x0002,
// Exit instruction (maybe conditional.)
IRFLAG_EXIT = 0x0004,
// Instruction like Interpret which may read anything, but not an exit.
IRFLAG_BARRIER = 0x0008,
};
2016-05-06 23:45:37 +02:00
struct IRMeta {
IROp op;
const char *name;
const char types[5]; // GGG
2016-05-06 23:45:37 +02:00
u32 flags;
};
// 64 bits.
2016-05-06 23:45:37 +02:00
struct IRInst {
IROp op;
union {
2023-07-20 19:21:00 -07:00
IRReg dest;
IRReg src3;
2016-05-06 23:45:37 +02:00
};
2023-07-20 19:21:00 -07:00
IRReg src1;
IRReg src2;
u32 constant;
2016-05-06 23:45:37 +02:00
};
// Returns the new PC.
u32 IRInterpret(MIPSState *ms, const IRInst *inst, int count);
2016-05-06 23:45:37 +02:00
// Each IR block gets a constant pool.
class IRWriter {
public:
IRWriter &operator =(const IRWriter &w) {
insts_ = w.insts_;
return *this;
}
IRWriter &operator =(IRWriter &&w) {
insts_ = std::move(w.insts_);
return *this;
}
2016-05-06 23:45:37 +02:00
void Write(IROp op, u8 dst = 0, u8 src1 = 0, u8 src2 = 0);
void Write(IROp op, IRReg dst, IRReg src1, IRReg src2, uint32_t c) {
AddConstant(c);
Write(op, dst, src1, src2);
}
void Write(IRInst inst) {
insts_.push_back(inst);
}
2016-05-06 23:45:37 +02:00
void WriteSetConstant(u8 dst, u32 value);
int AddConstant(u32 value);
int AddConstantFloat(float value);
void Reserve(size_t s) {
insts_.reserve(s);
}
2016-05-06 23:45:37 +02:00
void Clear() {
insts_.clear();
}
const std::vector<IRInst> &GetInstructions() const { return insts_; }
2016-05-06 23:45:37 +02:00
private:
std::vector<IRInst> insts_;
u32 nextConst_ = 0;
2016-05-06 23:45:37 +02:00
};
struct IROptions {
uint32_t disableFlags;
bool unalignedLoadStore;
bool unalignedLoadStoreVec4;
bool preferVec4;
bool preferVec4Dot;
};
const IRMeta *GetIRMeta(IROp op);
void DisassembleIR(char *buf, size_t bufsize, IRInst inst);
2016-05-07 17:37:19 +02:00
void InitIR();