#pragma once
#include <cstdint>
#include <vector>
#include <utility>
#include "Common/CommonTypes.h"
#include "Core/MIPS/MIPS.h"
enum class IROp : uint8_t {
SetConst,
SetConstF,
Mov,
Add,
Sub,
Neg,
Not,
And,
Or,
Xor,
AddConst,
OptAddConst,
SubConst,
AndConst,
OrConst,
XorConst,
OptAndConst,
OptOrConst,
Shl,
Shr,
Sar,
Ror,
ShlImm,
ShrImm,
SarImm,
RorImm,
Slt,
SltConst,
SltU,
SltUConst,
Clz,
MovZ,
MovNZ,
Max,
Min,
BSwap16,
BSwap32,
MtLo,
MtHi,
MfLo,
MfHi,
Mult,
MultU,
Madd,
MaddU,
Msub,
MsubU,
Div,
DivU,
Load8,
Load8Ext,
Load16,
Load16Ext,
Load32,
Load32Left,
Load32Right,
Load32Linked,
LoadFloat,
LoadVec4,
Store8,
Store16,
Store32,
Store32Left,
Store32Right,
Store32Conditional,
StoreFloat,
StoreVec4,
Ext8to32,
Ext16to32,
ReverseBits,
FAdd,
FSub,
FMul,
FDiv,
FMin,
FMax,
FMov,
FSqrt,
FNeg,
FAbs,
FSign,
FRound,
FTrunc,
FCeil,
FFloor,
FCvtWS,
FCvtSW,
FCvtScaledWS,
FCvtScaledSW,
FMovFromGPR,
OptFCvtSWFromGPR,
FMovToGPR,
OptFMovToGPRShr8,
FSat0_1,
FSatMinus1_1,
FpCondFromReg,
FpCondToReg,
FpCtrlFromReg,
FpCtrlToReg,
VfpuCtrlToReg,
FCmp,
FCmovVfpuCC,
FCmpVfpuBit,
FCmpVfpuAggregate,
RestoreRoundingMode,
ApplyRoundingMode,
UpdateRoundingMode,
SetCtrlVFPU,
SetCtrlVFPUReg,
SetCtrlVFPUFReg,
Vec4Init,
Vec4Shuffle,
Vec4Blend,
Vec4Mov,
Vec4Add,
Vec4Sub,
Vec4Mul,
Vec4Div,
Vec4Scale,
Vec4Dot,
Vec4Neg,
Vec4Abs,
Vec2Unpack16To31,
Vec2Unpack16To32,
Vec4Unpack8To32,
Vec4DuplicateUpperBitsAndShift1,
Vec4ClampToZero,
Vec2ClampToZero,
Vec4Pack31To8,
Vec4Pack32To8,
Vec2Pack31To16,
Vec2Pack32To16,
FSin,
FCos,
FRSqrt,
FRecip,
FAsin,
Interpret,
Downcount,
ExitToConst,
ExitToReg,
ExitToConstIfEq,
ExitToConstIfNeq,
ExitToConstIfGtZ,
ExitToConstIfGeZ,
ExitToConstIfLtZ,
ExitToConstIfLeZ,
ExitToConstIfFpTrue,
ExitToConstIfFpFalse,
ExitToPC,
Syscall,
SetPC,
SetPCConst,
CallReplacement,
Break,
Breakpoint,
MemoryCheck,
ValidateAddress8,
ValidateAddress16,
ValidateAddress32,
ValidateAddress128,
LogIRBlock,
Nop,
Bad,
};
enum IRComparison {
Greater,
GreaterEqual,
Less,
LessEqual,
Equal,
NotEqual,
Bad,
};
enum class Vec4Init {
AllZERO,
AllONE,
AllMinusONE,
Set_1000,
Set_0100,
Set_0010,
Set_0001,
};
enum class IRRoundMode : uint8_t {
RINT_0 = 0,
CAST_1 = 1,
CEIL_2 = 2,
FLOOR_3 = 3,
};
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,
EqualUnordered,
LessOrdered,
LessUnordered,
LessEqualOrdered,
LessEqualUnordered,
};
typedef u8 IRReg;
enum : IRReg {
IRTEMP_0 = 192,
IRTEMP_1,
IRTEMP_2,
IRTEMP_3,
IRTEMP_LHS,
IRTEMP_RHS,
IRTEMP_LR_ADDR,
IRTEMP_LR_VALUE,
IRTEMP_LR_MASK,
IRTEMP_LR_SHIFT,
IRVTEMP_PFX_S = 224 - 32,
IRVTEMP_PFX_T = 228 - 32,
IRVTEMP_PFX_D = 232 - 32,
IRVTEMP_0 = 236 - 32,
IRREG_VFPU_CTRL_BASE = 208,
IRREG_VFPU_CC = 211,
IRREG_LO = 242,
IRREG_HI = 243,
IRREG_FCR31 = 244,
IRREG_FPCOND = 245,
IRREG_LLBIT = 250,
};
enum IRFlags {
IRFLAG_SRC3 = 0x0001,
IRFLAG_SRC3DST = 0x0002,
IRFLAG_EXIT = 0x0004,
IRFLAG_BARRIER = 0x0008,
};
struct IRMeta {
IROp op;
const char *name;
char types[5];
u32 flags;
};
struct IRInst {
IROp op;
union {
IRReg dest;
IRReg src3;
};
IRReg src1;
IRReg src2;
u32 constant;
};
u32 IRInterpret(MIPSState *ms, const IRInst *inst);
class IRWriter {
public:
IRWriter &operator =(const IRWriter &w) {
insts_ = w.insts_;
return *this;
}
IRWriter &operator =(IRWriter &&w) noexcept {
insts_ = std::move(w.insts_);
return *this;
}
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);
}
void WriteSetConstant(u8 dst, u32 value);
int AddConstant(u32 value);
int AddConstantFloat(float value);
void Reserve(size_t s) {
insts_.reserve(s);
}
void Clear() {
insts_.clear();
}
void ReplaceConstant(size_t instNumber, u32 newConstant);
const std::vector<IRInst> &GetInstructions() const { return insts_; }
private:
std::vector<IRInst> insts_;
u32 nextConst_ = 0;
};
struct IROptions {
uint32_t disableFlags;
bool unalignedLoadStore;
bool unalignedLoadStoreVec4;
bool preferVec4;
bool preferVec4Dot;
bool optimizeForInterpreter;
};
const IRMeta *GetIRMeta(IROp op);
void DisassembleIR(char *buf, size_t bufsize, IRInst inst);
void InitIR();