rpcsx/rpcs3/Emu/Cell/PPUAnalyser.h

1690 lines
28 KiB
C
Raw Normal View History

2016-06-05 12:14:20 +02:00
#pragma once
2017-04-16 03:31:58 +02:00
#include <string>
#include <map>
#include <set>
#include "util/types.hpp"
#include "util/endian.hpp"
2016-08-07 21:01:27 +02:00
#include "Utilities/bit_set.h"
2017-10-13 04:13:43 +02:00
#include "PPUOpcodes.h"
// PPU Function Attributes
enum class ppu_attr : u32
{
2016-07-13 01:54:34 +02:00
known_addr,
known_size,
no_return,
no_size,
has_mfvscr,
2016-08-07 21:01:27 +02:00
__bitset_enum_max
};
// PPU Function Information
struct ppu_function
{
u32 addr = 0;
u32 toc = 0;
u32 size = 0;
2016-08-07 21:01:27 +02:00
bs_t<ppu_attr> attr{};
u32 stack_frame = 0;
2017-04-06 15:57:32 +02:00
u32 trampoline = 0;
2021-04-03 18:38:02 +02:00
std::map<u32, u32> blocks{}; // Basic blocks: addr -> size
std::set<u32> calls{}; // Set of called functions
std::set<u32> callers{};
std::string name{}; // Function name
};
2017-06-26 15:55:35 +02:00
// PPU Relocation Information
struct ppu_reloc
{
2017-07-01 01:08:51 +02:00
u32 addr;
2017-06-26 15:55:35 +02:00
u32 type;
2017-07-01 01:08:51 +02:00
u64 data;
// Operator for sorting
bool operator <(const ppu_reloc& rhs) const
{
return addr < rhs.addr;
}
bool operator <(u32 rhs) const
{
return addr < rhs;
}
2017-06-26 15:55:35 +02:00
};
// PPU Segment Information
struct ppu_segment
{
u32 addr;
u32 size;
u32 type;
u32 flags;
2017-08-22 23:42:12 +02:00
u32 filesz;
2017-06-26 15:55:35 +02:00
};
2017-02-26 16:56:31 +01:00
// PPU Module Information
struct ppu_module
{
ppu_module() = default;
ppu_module(const ppu_module&) = delete;
ppu_module(ppu_module&&) = default;
ppu_module& operator=(const ppu_module&) = delete;
ppu_module& operator=(ppu_module&&) = default;
uchar sha1[20]{};
std::string name{};
std::string path{};
s64 offset = 0; // Offset of file
std::string cache{};
std::vector<ppu_reloc> relocs{};
std::vector<ppu_segment> segs{};
std::vector<ppu_segment> secs{};
std::vector<ppu_function> funcs{};
2017-07-01 01:08:51 +02:00
// Copy info without functions
void copy_part(const ppu_module& info)
{
std::memcpy(sha1, info.sha1, sizeof(sha1));
name = info.name;
path = info.path;
relocs = info.relocs;
segs = info.segs;
secs = info.secs;
}
void analyse(u32 lib_toc, u32 entry, u32 end, const std::basic_string<u32>& applied);
2017-07-01 01:08:51 +02:00
void validate(u32 reloc);
2017-02-26 16:56:31 +01:00
};
// Aux
struct ppu_pattern
{
be_t<u32> opcode;
be_t<u32> mask;
ppu_pattern() = default;
ppu_pattern(u32 op)
: opcode(op)
, mask(0xffffffff)
{
}
ppu_pattern(u32 op, u32 ign)
: opcode(op & ~ign)
, mask(~ign)
{
}
};
struct ppu_pattern_array
{
const ppu_pattern* ptr;
2020-12-18 08:39:54 +01:00
usz count;
2020-12-18 08:39:54 +01:00
template <usz N>
constexpr ppu_pattern_array(const ppu_pattern(&array)[N])
: ptr(array)
, count(N)
{
}
constexpr const ppu_pattern* begin() const
{
return ptr;
}
constexpr const ppu_pattern* end() const
{
return ptr + count;
}
};
struct ppu_pattern_matrix
{
const ppu_pattern_array* ptr;
2020-12-18 08:39:54 +01:00
usz count;
2020-12-18 08:39:54 +01:00
template <usz N>
constexpr ppu_pattern_matrix(const ppu_pattern_array(&array)[N])
: ptr(array)
, count(N)
{
}
constexpr const ppu_pattern_array* begin() const
{
return ptr;
}
constexpr const ppu_pattern_array* end() const
{
return ptr + count;
}
};
2016-06-05 12:14:20 +02:00
// PPU Instruction Type
struct ppu_itype
{
enum type
{
UNK = 0,
MFVSCR,
MTVSCR,
VADDCUW,
VADDFP,
VADDSBS,
VADDSHS,
VADDSWS,
VADDUBM,
VADDUBS,
VADDUHM,
VADDUHS,
VADDUWM,
VADDUWS,
VAND,
VANDC,
VAVGSB,
VAVGSH,
VAVGSW,
VAVGUB,
VAVGUH,
VAVGUW,
VCFSX,
VCFUX,
VCMPBFP,
VCMPEQFP,
VCMPEQUB,
VCMPEQUH,
VCMPEQUW,
VCMPGEFP,
VCMPGTFP,
VCMPGTSB,
VCMPGTSH,
VCMPGTSW,
VCMPGTUB,
VCMPGTUH,
VCMPGTUW,
VCTSXS,
VCTUXS,
VEXPTEFP,
VLOGEFP,
VMADDFP,
VMAXFP,
VMAXSB,
VMAXSH,
VMAXSW,
VMAXUB,
VMAXUH,
VMAXUW,
VMHADDSHS,
VMHRADDSHS,
VMINFP,
VMINSB,
VMINSH,
VMINSW,
VMINUB,
VMINUH,
VMINUW,
VMLADDUHM,
VMRGHB,
VMRGHH,
VMRGHW,
VMRGLB,
VMRGLH,
VMRGLW,
VMSUMMBM,
VMSUMSHM,
VMSUMSHS,
VMSUMUBM,
VMSUMUHM,
VMSUMUHS,
VMULESB,
VMULESH,
VMULEUB,
VMULEUH,
VMULOSB,
VMULOSH,
VMULOUB,
VMULOUH,
VNMSUBFP,
VNOR,
VOR,
VPERM,
VPKPX,
VPKSHSS,
VPKSHUS,
VPKSWSS,
VPKSWUS,
VPKUHUM,
VPKUHUS,
VPKUWUM,
VPKUWUS,
VREFP,
VRFIM,
VRFIN,
VRFIP,
VRFIZ,
VRLB,
VRLH,
VRLW,
VRSQRTEFP,
VSEL,
VSL,
VSLB,
VSLDOI,
VSLH,
VSLO,
VSLW,
VSPLTB,
VSPLTH,
VSPLTISB,
VSPLTISH,
VSPLTISW,
VSPLTW,
VSR,
VSRAB,
VSRAH,
VSRAW,
VSRB,
VSRH,
VSRO,
VSRW,
VSUBCUW,
VSUBFP,
VSUBSBS,
VSUBSHS,
VSUBSWS,
VSUBUBM,
VSUBUBS,
VSUBUHM,
VSUBUHS,
VSUBUWM,
VSUBUWS,
VSUMSWS,
VSUM2SWS,
VSUM4SBS,
VSUM4SHS,
VSUM4UBS,
VUPKHPX,
VUPKHSB,
VUPKHSH,
VUPKLPX,
VUPKLSB,
VUPKLSH,
VXOR,
TDI,
TWI,
MULLI,
SUBFIC,
CMPLI,
CMPI,
ADDIC,
ADDI,
ADDIS,
BC,
SC,
B,
MCRF,
BCLR,
CRNOR,
CRANDC,
ISYNC,
CRXOR,
CRNAND,
CRAND,
CREQV,
CRORC,
CROR,
BCCTR,
RLWIMI,
RLWINM,
RLWNM,
ORI,
ORIS,
XORI,
XORIS,
ANDI,
ANDIS,
RLDICL,
RLDICR,
RLDIC,
RLDIMI,
RLDCL,
RLDCR,
CMP,
TW,
LVSL,
LVEBX,
SUBFC,
ADDC,
MULHDU,
MULHWU,
MFOCRF,
LWARX,
LDX,
LWZX,
SLW,
CNTLZW,
SLD,
AND,
CMPL,
LVSR,
LVEHX,
SUBF,
LDUX,
DCBST,
LWZUX,
CNTLZD,
ANDC,
TD,
LVEWX,
MULHD,
MULHW,
LDARX,
DCBF,
LBZX,
LVX,
NEG,
LBZUX,
NOR,
STVEBX,
SUBFE,
ADDE,
MTOCRF,
STDX,
STWCX,
STWX,
STVEHX,
STDUX,
STWUX,
STVEWX,
SUBFZE,
ADDZE,
STDCX,
STBX,
STVX,
SUBFME,
MULLD,
ADDME,
MULLW,
DCBTST,
STBUX,
ADD,
DCBT,
LHZX,
EQV,
ECIWX,
LHZUX,
XOR,
MFSPR,
LWAX,
DST,
LHAX,
LVXL,
MFTB,
LWAUX,
DSTST,
LHAUX,
STHX,
ORC,
ECOWX,
STHUX,
OR,
DIVDU,
DIVWU,
MTSPR,
DCBI,
NAND,
STVXL,
DIVD,
DIVW,
LVLX,
LDBRX,
LSWX,
LWBRX,
LFSX,
SRW,
SRD,
LVRX,
LSWI,
LFSUX,
SYNC,
LFDX,
LFDUX,
STVLX,
STDBRX,
STSWX,
STWBRX,
STFSX,
STVRX,
STFSUX,
STSWI,
STFDX,
STFDUX,
LVLXL,
LHBRX,
SRAW,
SRAD,
LVRXL,
DSS,
SRAWI,
SRADI,
EIEIO,
STVLXL,
STHBRX,
EXTSH,
STVRXL,
EXTSB,
STFIWX,
EXTSW,
ICBI,
DCBZ,
LWZ,
LWZU,
LBZ,
LBZU,
STW,
STWU,
STB,
STBU,
LHZ,
LHZU,
LHA,
LHAU,
STH,
STHU,
LMW,
STMW,
LFS,
LFSU,
LFD,
LFDU,
STFS,
STFSU,
STFD,
STFDU,
LD,
LDU,
LWA,
STD,
STDU,
FDIVS,
FSUBS,
FADDS,
FSQRTS,
FRES,
FMULS,
FMADDS,
FMSUBS,
FNMSUBS,
FNMADDS,
MTFSB1,
MCRFS,
MTFSB0,
MTFSFI,
MFFS,
MTFSF,
FCMPU,
FRSP,
FCTIW,
FCTIWZ,
FDIV,
FSUB,
FADD,
FSQRT,
FSEL,
FMUL,
FRSQRTE,
FMSUB,
FMADD,
FNMSUB,
FNMADD,
FCMPO,
FNEG,
FMR,
FNABS,
FABS,
FCTID,
FCTIDZ,
FCFID,
};
// Enable address-of operator for ppu_decoder<>
friend constexpr type operator &(type value)
{
return value;
}
};
2016-06-07 22:24:20 +02:00
struct ppu_iname
{
#define NAME(x) static constexpr const char& x = *#x;
2016-06-07 22:24:20 +02:00
NAME(UNK)
NAME(MFVSCR)
NAME(MTVSCR)
NAME(VADDCUW)
NAME(VADDFP)
NAME(VADDSBS)
NAME(VADDSHS)
NAME(VADDSWS)
NAME(VADDUBM)
NAME(VADDUBS)
NAME(VADDUHM)
NAME(VADDUHS)
NAME(VADDUWM)
NAME(VADDUWS)
NAME(VAND)
NAME(VANDC)
NAME(VAVGSB)
NAME(VAVGSH)
NAME(VAVGSW)
NAME(VAVGUB)
NAME(VAVGUH)
NAME(VAVGUW)
NAME(VCFSX)
NAME(VCFUX)
NAME(VCMPBFP)
NAME(VCMPEQFP)
NAME(VCMPEQUB)
NAME(VCMPEQUH)
NAME(VCMPEQUW)
NAME(VCMPGEFP)
NAME(VCMPGTFP)
NAME(VCMPGTSB)
NAME(VCMPGTSH)
NAME(VCMPGTSW)
NAME(VCMPGTUB)
NAME(VCMPGTUH)
NAME(VCMPGTUW)
NAME(VCTSXS)
NAME(VCTUXS)
NAME(VEXPTEFP)
NAME(VLOGEFP)
NAME(VMADDFP)
NAME(VMAXFP)
NAME(VMAXSB)
NAME(VMAXSH)
NAME(VMAXSW)
NAME(VMAXUB)
NAME(VMAXUH)
NAME(VMAXUW)
NAME(VMHADDSHS)
NAME(VMHRADDSHS)
NAME(VMINFP)
NAME(VMINSB)
NAME(VMINSH)
NAME(VMINSW)
NAME(VMINUB)
NAME(VMINUH)
NAME(VMINUW)
NAME(VMLADDUHM)
NAME(VMRGHB)
NAME(VMRGHH)
NAME(VMRGHW)
NAME(VMRGLB)
NAME(VMRGLH)
NAME(VMRGLW)
NAME(VMSUMMBM)
NAME(VMSUMSHM)
NAME(VMSUMSHS)
NAME(VMSUMUBM)
NAME(VMSUMUHM)
NAME(VMSUMUHS)
NAME(VMULESB)
NAME(VMULESH)
NAME(VMULEUB)
NAME(VMULEUH)
NAME(VMULOSB)
NAME(VMULOSH)
NAME(VMULOUB)
NAME(VMULOUH)
NAME(VNMSUBFP)
NAME(VNOR)
NAME(VOR)
NAME(VPERM)
NAME(VPKPX)
NAME(VPKSHSS)
NAME(VPKSHUS)
NAME(VPKSWSS)
NAME(VPKSWUS)
NAME(VPKUHUM)
NAME(VPKUHUS)
NAME(VPKUWUM)
NAME(VPKUWUS)
NAME(VREFP)
NAME(VRFIM)
NAME(VRFIN)
NAME(VRFIP)
NAME(VRFIZ)
NAME(VRLB)
NAME(VRLH)
NAME(VRLW)
NAME(VRSQRTEFP)
NAME(VSEL)
NAME(VSL)
NAME(VSLB)
NAME(VSLDOI)
NAME(VSLH)
NAME(VSLO)
NAME(VSLW)
NAME(VSPLTB)
NAME(VSPLTH)
NAME(VSPLTISB)
NAME(VSPLTISH)
NAME(VSPLTISW)
NAME(VSPLTW)
NAME(VSR)
NAME(VSRAB)
NAME(VSRAH)
NAME(VSRAW)
NAME(VSRB)
NAME(VSRH)
NAME(VSRO)
NAME(VSRW)
NAME(VSUBCUW)
NAME(VSUBFP)
NAME(VSUBSBS)
NAME(VSUBSHS)
NAME(VSUBSWS)
NAME(VSUBUBM)
NAME(VSUBUBS)
NAME(VSUBUHM)
NAME(VSUBUHS)
NAME(VSUBUWM)
NAME(VSUBUWS)
NAME(VSUMSWS)
NAME(VSUM2SWS)
NAME(VSUM4SBS)
NAME(VSUM4SHS)
NAME(VSUM4UBS)
NAME(VUPKHPX)
NAME(VUPKHSB)
NAME(VUPKHSH)
NAME(VUPKLPX)
NAME(VUPKLSB)
NAME(VUPKLSH)
NAME(VXOR)
NAME(TDI)
NAME(TWI)
NAME(MULLI)
NAME(SUBFIC)
NAME(CMPLI)
NAME(CMPI)
NAME(ADDIC)
NAME(ADDI)
NAME(ADDIS)
NAME(BC)
NAME(SC)
NAME(B)
NAME(MCRF)
NAME(BCLR)
NAME(CRNOR)
NAME(CRANDC)
NAME(ISYNC)
NAME(CRXOR)
NAME(CRNAND)
NAME(CRAND)
NAME(CREQV)
NAME(CRORC)
NAME(CROR)
NAME(BCCTR)
NAME(RLWIMI)
NAME(RLWINM)
NAME(RLWNM)
NAME(ORI)
NAME(ORIS)
NAME(XORI)
NAME(XORIS)
NAME(ANDI)
NAME(ANDIS)
NAME(RLDICL)
NAME(RLDICR)
NAME(RLDIC)
NAME(RLDIMI)
NAME(RLDCL)
NAME(RLDCR)
NAME(CMP)
NAME(TW)
NAME(LVSL)
NAME(LVEBX)
NAME(SUBFC)
NAME(ADDC)
NAME(MULHDU)
NAME(MULHWU)
NAME(MFOCRF)
NAME(LWARX)
NAME(LDX)
NAME(LWZX)
NAME(SLW)
NAME(CNTLZW)
NAME(SLD)
NAME(AND)
NAME(CMPL)
NAME(LVSR)
NAME(LVEHX)
NAME(SUBF)
NAME(LDUX)
NAME(DCBST)
NAME(LWZUX)
NAME(CNTLZD)
NAME(ANDC)
NAME(TD)
NAME(LVEWX)
NAME(MULHD)
NAME(MULHW)
NAME(LDARX)
NAME(DCBF)
NAME(LBZX)
NAME(LVX)
NAME(NEG)
NAME(LBZUX)
NAME(NOR)
NAME(STVEBX)
NAME(SUBFE)
NAME(ADDE)
NAME(MTOCRF)
NAME(STDX)
NAME(STWCX)
NAME(STWX)
NAME(STVEHX)
NAME(STDUX)
NAME(STWUX)
NAME(STVEWX)
NAME(SUBFZE)
NAME(ADDZE)
NAME(STDCX)
NAME(STBX)
NAME(STVX)
NAME(SUBFME)
NAME(MULLD)
NAME(ADDME)
NAME(MULLW)
NAME(DCBTST)
NAME(STBUX)
NAME(ADD)
NAME(DCBT)
NAME(LHZX)
NAME(EQV)
NAME(ECIWX)
NAME(LHZUX)
NAME(XOR)
NAME(MFSPR)
NAME(LWAX)
NAME(DST)
NAME(LHAX)
NAME(LVXL)
NAME(MFTB)
NAME(LWAUX)
NAME(DSTST)
NAME(LHAUX)
NAME(STHX)
NAME(ORC)
NAME(ECOWX)
NAME(STHUX)
NAME(OR)
NAME(DIVDU)
NAME(DIVWU)
NAME(MTSPR)
NAME(DCBI)
NAME(NAND)
NAME(STVXL)
NAME(DIVD)
NAME(DIVW)
NAME(LVLX)
NAME(LDBRX)
NAME(LSWX)
NAME(LWBRX)
NAME(LFSX)
NAME(SRW)
NAME(SRD)
NAME(LVRX)
NAME(LSWI)
NAME(LFSUX)
NAME(SYNC)
NAME(LFDX)
NAME(LFDUX)
NAME(STVLX)
NAME(STDBRX)
NAME(STSWX)
NAME(STWBRX)
NAME(STFSX)
NAME(STVRX)
NAME(STFSUX)
NAME(STSWI)
NAME(STFDX)
NAME(STFDUX)
NAME(LVLXL)
NAME(LHBRX)
NAME(SRAW)
NAME(SRAD)
NAME(LVRXL)
NAME(DSS)
NAME(SRAWI)
NAME(SRADI)
NAME(EIEIO)
NAME(STVLXL)
NAME(STHBRX)
NAME(EXTSH)
NAME(STVRXL)
NAME(EXTSB)
NAME(STFIWX)
NAME(EXTSW)
NAME(ICBI)
NAME(DCBZ)
NAME(LWZ)
NAME(LWZU)
NAME(LBZ)
NAME(LBZU)
NAME(STW)
NAME(STWU)
NAME(STB)
NAME(STBU)
NAME(LHZ)
NAME(LHZU)
NAME(LHA)
NAME(LHAU)
NAME(STH)
NAME(STHU)
NAME(LMW)
NAME(STMW)
NAME(LFS)
NAME(LFSU)
NAME(LFD)
NAME(LFDU)
NAME(STFS)
NAME(STFSU)
NAME(STFD)
NAME(STFDU)
NAME(LD)
NAME(LDU)
NAME(LWA)
NAME(STD)
NAME(STDU)
NAME(FDIVS)
NAME(FSUBS)
NAME(FADDS)
NAME(FSQRTS)
NAME(FRES)
NAME(FMULS)
NAME(FMADDS)
NAME(FMSUBS)
NAME(FNMSUBS)
NAME(FNMADDS)
NAME(MTFSB1)
NAME(MCRFS)
NAME(MTFSB0)
NAME(MTFSFI)
NAME(MFFS)
NAME(MTFSF)
NAME(FCMPU)
NAME(FRSP)
NAME(FCTIW)
NAME(FCTIWZ)
NAME(FDIV)
NAME(FSUB)
NAME(FADD)
NAME(FSQRT)
NAME(FSEL)
NAME(FMUL)
NAME(FRSQRTE)
NAME(FMSUB)
NAME(FMADD)
NAME(FNMSUB)
NAME(FNMADD)
NAME(FCMPO)
NAME(FNEG)
NAME(FMR)
NAME(FNABS)
NAME(FABS)
NAME(FCTID)
NAME(FCTIDZ)
NAME(FCFID)
#undef NAME
};
2017-10-13 04:13:43 +02:00
// PPU Analyser Context
struct ppu_acontext
{
// General-purpose register range
struct spec_gpr
{
// Integral range: normalized undef = (0;UINT64_MAX), unnormalized undefs are possible (when max = min - 1)
// Bit range: constant 0 = (0;0), constant 1 = (1;1), normalized undef = (0;1), unnormalized undef = (1;0)
2018-05-12 10:03:01 +02:00
u64 imin = 0ull; // Integral range begin
2019-06-28 07:24:28 +02:00
u64 imax = ~0ull; // Integral range end
2018-05-12 10:03:01 +02:00
u64 bmin = 0ull; // Bit range begin
2019-06-28 07:24:28 +02:00
u64 bmax = ~0ull; // Bit range end
2017-10-13 04:13:43 +02:00
void set_undef()
{
imin = 0;
imax = -1;
bmin = 0;
bmax = -1;
}
// (Number of possible values - 1), 0 = const
u64 div() const
{
return imax - imin;
}
// Return zero bits for zeros, ones for ones or undefs
u64 mask() const
{
return bmin | bmax;
}
// Return one bits for ones, zeros for zeros or undefs
u64 ones() const
{
return bmin & bmax;
}
// Return one bits for undefs
u64 undefs() const
{
return bmin ^ bmax;
}
// Return number of trailing zero bits
u64 tz() const
{
return std::countr_zero(mask());
2017-10-13 04:13:43 +02:00
}
// Range NOT
spec_gpr operator ~() const
{
spec_gpr r;
r.imin = ~imax;
r.imax = ~imin;
r.bmin = ~bmax;
r.bmax = ~bmin;
return r;
}
// Range ADD
spec_gpr operator +(const spec_gpr& rhs) const
{
spec_gpr r{};
const u64 adiv = div();
const u64 bdiv = rhs.div();
// Check overflow, generate normalized range
if (adiv != umax && bdiv != umax && adiv <= adiv + bdiv)
2017-10-13 04:13:43 +02:00
{
r = range(imin + rhs.imin, imax + rhs.imax);
}
// Carry for bitrange computation
u64 cmin = 0;
u64 cmax = 0;
const u64 amask = mask();
const u64 bmask = rhs.mask();
const u64 aones = ones();
const u64 bones = rhs.ones();
for (u32 i = 0; i < 64; i++)
{
cmin += ((amask >> i) & 1) + ((bmask >> i) & 1);
cmax += ((aones >> i) & 1) + ((bones >> i) & 1);
// Discover some constant bits
if (cmin == cmax)
{
r.bmin |= (cmin & 1) << i;
r.bmax &= ~((~cmin & 1) << i);
}
cmin >>= 1;
cmax >>= 1;
}
return r;
}
// Range AND
spec_gpr operator &(const spec_gpr& rhs) const
{
// Ignore inverted ranges (TODO)
if (imin > imax || rhs.imin > rhs.imax)
{
return approx(ones() & rhs.ones(), mask() & rhs.mask());
}
// Const (TODO: remove when unnecessary)
if (imin == imax && rhs.imin == rhs.imax)
{
return fixed(imin & rhs.imin);
}
// Swap (TODO: remove when unnecessary)
if (imin == imax || rhs.undefs() > undefs())
{
return rhs & *this;
}
// Copy and attempt to partially preserve integral range
spec_gpr r = *this;
for (u32 i = 63; ~i; i--)
{
const u64 m = 1ull << i;
if (!(rhs.mask() & m))
{
if (r.undefs() & m)
{
// undef -> 0
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin &= ~m;
r.imax &= ~m;
}
else if (r.ones() & m)
{
// 1 -> 0
if ((r.imin ^ r.imax) > (m - 1))
{
r.imin &= ~(m - 1);
r.imax |= (m - 1);
}
r.imin &= ~m;
r.imax &= ~m;
}
}
else if (rhs.undefs() & m)
{
// -> undef
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin &= ~m;
r.imax |= m;
}
}
r.bmin = ones() & rhs.ones();
r.bmax = mask() & rhs.mask();
return r;
}
// Range OR
spec_gpr operator |(const spec_gpr& rhs) const
{
// Ignore inverted ranges (TODO)
if (imin > imax || rhs.imin > rhs.imax)
{
return approx(ones() | rhs.ones(), mask() | rhs.mask());
}
// Const (TODO: remove when unnecessary)
if (imin == imax && rhs.imin == rhs.imax)
{
return fixed(imin | rhs.imin);
}
// Swap (TODO: remove when unnecessary)
if (imin == imax || rhs.undefs() > undefs())
{
return rhs | *this;
}
// Copy and attempt to partially preserve integral range
spec_gpr r = *this;
for (u32 i = 63; ~i; i--)
{
const u64 m = 1ull << i;
if (rhs.ones() & m)
{
if (r.undefs() & m)
{
// undef -> 1
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin |= m;
r.imax |= m;
}
else if (!(r.mask() & m))
{
// 0 -> 1
if ((r.imin ^ r.imax) > (m - 1))
{
r.imin &= ~(m - 1);
r.imax |= (m - 1);
}
r.imin |= m;
r.imax |= m;
}
}
else if (rhs.undefs() & m)
{
// -> undef
r.imin &= ~(m - 1);
r.imax |= (m - 1);
r.imin &= ~m;
r.imax |= m;
}
}
r.bmin = ones() | rhs.ones();
r.bmax = mask() | rhs.mask();
return r;
}
// Range XOR
2021-04-09 21:12:47 +02:00
spec_gpr operator ^(const spec_gpr& rhs) const
2017-10-13 04:13:43 +02:00
{
return (~*this & rhs) | (*this & ~rhs);
}
// Check whether the value is in range
bool test(u64 value) const
{
if (imin <= imax)
{
if (value < imin || value > imax)
{
return false;
}
}
else
{
if (value < imin && value > imax)
{
return false;
}
}
if ((value & mask()) != value)
{
return false;
}
if ((value | ones()) != value)
{
return false;
}
return true;
}
// Constant value
static spec_gpr fixed(u64 value)
{
spec_gpr r;
r.imin = value;
r.imax = value;
r.bmin = value;
r.bmax = value;
return r;
}
// Range (tz = number of constant trailing zeros)
static spec_gpr range(u64 min, u64 max, u64 tz = 0)
{
const u64 mask = tz < 64 ? ~0ull << tz : 0ull;
spec_gpr r;
r.bmin = 0;
r.bmax = mask;
// Normalize min/max for tz (TODO)
if (min < max)
{
// Inverted constant MSB mask
const u64 mix = ~0ull >> std::countl_zero(min ^ max);
2017-10-13 04:13:43 +02:00
r.bmin |= min & ~mix;
r.bmax &= max | mix;
r.imin = (min + ~mask) & mask;
r.imax = max & mask;
ensure(r.imin <= r.imax); // "Impossible range"
2017-10-13 04:13:43 +02:00
}
else
{
r.imin = min & mask;
r.imax = (max + ~mask) & mask;
ensure(r.imin >= r.imax); // "Impossible range"
2017-10-13 04:13:43 +02:00
}
// Fix const values
if (r.imin == r.imax)
{
r.bmin = r.imin;
r.bmax = r.imax;
}
return r;
}
// Make from bitrange (normalize, approximate range values)
static spec_gpr approx(u64 bmin, u64 bmax)
{
spec_gpr r;
r.imin = bmin & ~(bmin ^ bmax);
r.imax = bmax | (bmin ^ bmax);
r.bmin = bmin & ~(bmin ^ bmax);
r.bmax = bmax | (bmin ^ bmax);
return r;
}
} gpr[32]{};
// Vector registers (draft)
struct spec_vec
{
u8 imin8[16]{};
u8 imax8[16]{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
u16 imin16[8]{};
u16 imax16[8]{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
u32 imin32[4]{};
u32 imax32[4]{0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu};
u64 bmin64[2]{};
u64 bmax64[2]{0xffffffffffffffffull, 0xffffffffffffffffull};
};
// Info
u32 cia;
// Analyser step
void UNK(ppu_opcode_t);
void MFVSCR(ppu_opcode_t);
void MTVSCR(ppu_opcode_t);
void VADDCUW(ppu_opcode_t);
void VADDFP(ppu_opcode_t);
void VADDSBS(ppu_opcode_t);
void VADDSHS(ppu_opcode_t);
void VADDSWS(ppu_opcode_t);
void VADDUBM(ppu_opcode_t);
void VADDUBS(ppu_opcode_t);
void VADDUHM(ppu_opcode_t);
void VADDUHS(ppu_opcode_t);
void VADDUWM(ppu_opcode_t);
void VADDUWS(ppu_opcode_t);
void VAND(ppu_opcode_t);
void VANDC(ppu_opcode_t);
void VAVGSB(ppu_opcode_t);
void VAVGSH(ppu_opcode_t);
void VAVGSW(ppu_opcode_t);
void VAVGUB(ppu_opcode_t);
void VAVGUH(ppu_opcode_t);
void VAVGUW(ppu_opcode_t);
void VCFSX(ppu_opcode_t);
void VCFUX(ppu_opcode_t);
void VCMPBFP(ppu_opcode_t);
void VCMPEQFP(ppu_opcode_t);
void VCMPEQUB(ppu_opcode_t);
void VCMPEQUH(ppu_opcode_t);
void VCMPEQUW(ppu_opcode_t);
void VCMPGEFP(ppu_opcode_t);
void VCMPGTFP(ppu_opcode_t);
void VCMPGTSB(ppu_opcode_t);
void VCMPGTSH(ppu_opcode_t);
void VCMPGTSW(ppu_opcode_t);
void VCMPGTUB(ppu_opcode_t);
void VCMPGTUH(ppu_opcode_t);
void VCMPGTUW(ppu_opcode_t);
void VCTSXS(ppu_opcode_t);
void VCTUXS(ppu_opcode_t);
void VEXPTEFP(ppu_opcode_t);
void VLOGEFP(ppu_opcode_t);
void VMADDFP(ppu_opcode_t);
void VMAXFP(ppu_opcode_t);
void VMAXSB(ppu_opcode_t);
void VMAXSH(ppu_opcode_t);
void VMAXSW(ppu_opcode_t);
void VMAXUB(ppu_opcode_t);
void VMAXUH(ppu_opcode_t);
void VMAXUW(ppu_opcode_t);
void VMHADDSHS(ppu_opcode_t);
void VMHRADDSHS(ppu_opcode_t);
void VMINFP(ppu_opcode_t);
void VMINSB(ppu_opcode_t);
void VMINSH(ppu_opcode_t);
void VMINSW(ppu_opcode_t);
void VMINUB(ppu_opcode_t);
void VMINUH(ppu_opcode_t);
void VMINUW(ppu_opcode_t);
void VMLADDUHM(ppu_opcode_t);
void VMRGHB(ppu_opcode_t);
void VMRGHH(ppu_opcode_t);
void VMRGHW(ppu_opcode_t);
void VMRGLB(ppu_opcode_t);
void VMRGLH(ppu_opcode_t);
void VMRGLW(ppu_opcode_t);
void VMSUMMBM(ppu_opcode_t);
void VMSUMSHM(ppu_opcode_t);
void VMSUMSHS(ppu_opcode_t);
void VMSUMUBM(ppu_opcode_t);
void VMSUMUHM(ppu_opcode_t);
void VMSUMUHS(ppu_opcode_t);
void VMULESB(ppu_opcode_t);
void VMULESH(ppu_opcode_t);
void VMULEUB(ppu_opcode_t);
void VMULEUH(ppu_opcode_t);
void VMULOSB(ppu_opcode_t);
void VMULOSH(ppu_opcode_t);
void VMULOUB(ppu_opcode_t);
void VMULOUH(ppu_opcode_t);
void VNMSUBFP(ppu_opcode_t);
void VNOR(ppu_opcode_t);
void VOR(ppu_opcode_t);
void VPERM(ppu_opcode_t);
void VPKPX(ppu_opcode_t);
void VPKSHSS(ppu_opcode_t);
void VPKSHUS(ppu_opcode_t);
void VPKSWSS(ppu_opcode_t);
void VPKSWUS(ppu_opcode_t);
void VPKUHUM(ppu_opcode_t);
void VPKUHUS(ppu_opcode_t);
void VPKUWUM(ppu_opcode_t);
void VPKUWUS(ppu_opcode_t);
void VREFP(ppu_opcode_t);
void VRFIM(ppu_opcode_t);
void VRFIN(ppu_opcode_t);
void VRFIP(ppu_opcode_t);
void VRFIZ(ppu_opcode_t);
void VRLB(ppu_opcode_t);
void VRLH(ppu_opcode_t);
void VRLW(ppu_opcode_t);
void VRSQRTEFP(ppu_opcode_t);
void VSEL(ppu_opcode_t);
void VSL(ppu_opcode_t);
void VSLB(ppu_opcode_t);
void VSLDOI(ppu_opcode_t);
void VSLH(ppu_opcode_t);
void VSLO(ppu_opcode_t);
void VSLW(ppu_opcode_t);
void VSPLTB(ppu_opcode_t);
void VSPLTH(ppu_opcode_t);
void VSPLTISB(ppu_opcode_t);
void VSPLTISH(ppu_opcode_t);
void VSPLTISW(ppu_opcode_t);
void VSPLTW(ppu_opcode_t);
void VSR(ppu_opcode_t);
void VSRAB(ppu_opcode_t);
void VSRAH(ppu_opcode_t);
void VSRAW(ppu_opcode_t);
void VSRB(ppu_opcode_t);
void VSRH(ppu_opcode_t);
void VSRO(ppu_opcode_t);
void VSRW(ppu_opcode_t);
void VSUBCUW(ppu_opcode_t);
void VSUBFP(ppu_opcode_t);
void VSUBSBS(ppu_opcode_t);
void VSUBSHS(ppu_opcode_t);
void VSUBSWS(ppu_opcode_t);
void VSUBUBM(ppu_opcode_t);
void VSUBUBS(ppu_opcode_t);
void VSUBUHM(ppu_opcode_t);
void VSUBUHS(ppu_opcode_t);
void VSUBUWM(ppu_opcode_t);
void VSUBUWS(ppu_opcode_t);
void VSUMSWS(ppu_opcode_t);
void VSUM2SWS(ppu_opcode_t);
void VSUM4SBS(ppu_opcode_t);
void VSUM4SHS(ppu_opcode_t);
void VSUM4UBS(ppu_opcode_t);
void VUPKHPX(ppu_opcode_t);
void VUPKHSB(ppu_opcode_t);
void VUPKHSH(ppu_opcode_t);
void VUPKLPX(ppu_opcode_t);
void VUPKLSB(ppu_opcode_t);
void VUPKLSH(ppu_opcode_t);
void VXOR(ppu_opcode_t);
void TDI(ppu_opcode_t);
void TWI(ppu_opcode_t);
void MULLI(ppu_opcode_t);
void SUBFIC(ppu_opcode_t);
void CMPLI(ppu_opcode_t);
void CMPI(ppu_opcode_t);
void ADDIC(ppu_opcode_t);
void ADDI(ppu_opcode_t);
void ADDIS(ppu_opcode_t);
void BC(ppu_opcode_t);
void SC(ppu_opcode_t);
void B(ppu_opcode_t);
void MCRF(ppu_opcode_t);
void BCLR(ppu_opcode_t);
void CRNOR(ppu_opcode_t);
void CRANDC(ppu_opcode_t);
void ISYNC(ppu_opcode_t);
void CRXOR(ppu_opcode_t);
void CRNAND(ppu_opcode_t);
void CRAND(ppu_opcode_t);
void CREQV(ppu_opcode_t);
void CRORC(ppu_opcode_t);
void CROR(ppu_opcode_t);
void BCCTR(ppu_opcode_t);
void RLWIMI(ppu_opcode_t);
void RLWINM(ppu_opcode_t);
void RLWNM(ppu_opcode_t);
void ORI(ppu_opcode_t);
void ORIS(ppu_opcode_t);
void XORI(ppu_opcode_t);
void XORIS(ppu_opcode_t);
void ANDI(ppu_opcode_t);
void ANDIS(ppu_opcode_t);
void RLDICL(ppu_opcode_t);
void RLDICR(ppu_opcode_t);
void RLDIC(ppu_opcode_t);
void RLDIMI(ppu_opcode_t);
void RLDCL(ppu_opcode_t);
void RLDCR(ppu_opcode_t);
void CMP(ppu_opcode_t);
void TW(ppu_opcode_t);
void LVSL(ppu_opcode_t);
void LVEBX(ppu_opcode_t);
void SUBFC(ppu_opcode_t);
void ADDC(ppu_opcode_t);
void MULHDU(ppu_opcode_t);
void MULHWU(ppu_opcode_t);
void MFOCRF(ppu_opcode_t);
void LWARX(ppu_opcode_t);
void LDX(ppu_opcode_t);
void LWZX(ppu_opcode_t);
void SLW(ppu_opcode_t);
void CNTLZW(ppu_opcode_t);
void SLD(ppu_opcode_t);
void AND(ppu_opcode_t);
void CMPL(ppu_opcode_t);
void LVSR(ppu_opcode_t);
void LVEHX(ppu_opcode_t);
void SUBF(ppu_opcode_t);
void LDUX(ppu_opcode_t);
void DCBST(ppu_opcode_t);
void LWZUX(ppu_opcode_t);
void CNTLZD(ppu_opcode_t);
void ANDC(ppu_opcode_t);
void TD(ppu_opcode_t);
void LVEWX(ppu_opcode_t);
void MULHD(ppu_opcode_t);
void MULHW(ppu_opcode_t);
void LDARX(ppu_opcode_t);
void DCBF(ppu_opcode_t);
void LBZX(ppu_opcode_t);
void LVX(ppu_opcode_t);
void NEG(ppu_opcode_t);
void LBZUX(ppu_opcode_t);
void NOR(ppu_opcode_t);
void STVEBX(ppu_opcode_t);
void SUBFE(ppu_opcode_t);
void ADDE(ppu_opcode_t);
void MTOCRF(ppu_opcode_t);
void STDX(ppu_opcode_t);
void STWCX(ppu_opcode_t);
void STWX(ppu_opcode_t);
void STVEHX(ppu_opcode_t);
void STDUX(ppu_opcode_t);
void STWUX(ppu_opcode_t);
void STVEWX(ppu_opcode_t);
void SUBFZE(ppu_opcode_t);
void ADDZE(ppu_opcode_t);
void STDCX(ppu_opcode_t);
void STBX(ppu_opcode_t);
void STVX(ppu_opcode_t);
void SUBFME(ppu_opcode_t);
void MULLD(ppu_opcode_t);
void ADDME(ppu_opcode_t);
void MULLW(ppu_opcode_t);
void DCBTST(ppu_opcode_t);
void STBUX(ppu_opcode_t);
void ADD(ppu_opcode_t);
void DCBT(ppu_opcode_t);
void LHZX(ppu_opcode_t);
void EQV(ppu_opcode_t);
void ECIWX(ppu_opcode_t);
void LHZUX(ppu_opcode_t);
void XOR(ppu_opcode_t);
void MFSPR(ppu_opcode_t);
void LWAX(ppu_opcode_t);
void DST(ppu_opcode_t);
void LHAX(ppu_opcode_t);
void LVXL(ppu_opcode_t);
void MFTB(ppu_opcode_t);
void LWAUX(ppu_opcode_t);
void DSTST(ppu_opcode_t);
void LHAUX(ppu_opcode_t);
void STHX(ppu_opcode_t);
void ORC(ppu_opcode_t);
void ECOWX(ppu_opcode_t);
void STHUX(ppu_opcode_t);
void OR(ppu_opcode_t);
void DIVDU(ppu_opcode_t);
void DIVWU(ppu_opcode_t);
void MTSPR(ppu_opcode_t);
void DCBI(ppu_opcode_t);
void NAND(ppu_opcode_t);
void STVXL(ppu_opcode_t);
void DIVD(ppu_opcode_t);
void DIVW(ppu_opcode_t);
void LVLX(ppu_opcode_t);
void LDBRX(ppu_opcode_t);
void LSWX(ppu_opcode_t);
void LWBRX(ppu_opcode_t);
void LFSX(ppu_opcode_t);
void SRW(ppu_opcode_t);
void SRD(ppu_opcode_t);
void LVRX(ppu_opcode_t);
void LSWI(ppu_opcode_t);
void LFSUX(ppu_opcode_t);
void SYNC(ppu_opcode_t);
void LFDX(ppu_opcode_t);
void LFDUX(ppu_opcode_t);
void STVLX(ppu_opcode_t);
void STDBRX(ppu_opcode_t);
void STSWX(ppu_opcode_t);
void STWBRX(ppu_opcode_t);
void STFSX(ppu_opcode_t);
void STVRX(ppu_opcode_t);
void STFSUX(ppu_opcode_t);
void STSWI(ppu_opcode_t);
void STFDX(ppu_opcode_t);
void STFDUX(ppu_opcode_t);
void LVLXL(ppu_opcode_t);
void LHBRX(ppu_opcode_t);
void SRAW(ppu_opcode_t);
void SRAD(ppu_opcode_t);
void LVRXL(ppu_opcode_t);
void DSS(ppu_opcode_t);
void SRAWI(ppu_opcode_t);
void SRADI(ppu_opcode_t);
void EIEIO(ppu_opcode_t);
void STVLXL(ppu_opcode_t);
void STHBRX(ppu_opcode_t);
void EXTSH(ppu_opcode_t);
void STVRXL(ppu_opcode_t);
void EXTSB(ppu_opcode_t);
void STFIWX(ppu_opcode_t);
void EXTSW(ppu_opcode_t);
void ICBI(ppu_opcode_t);
void DCBZ(ppu_opcode_t);
void LWZ(ppu_opcode_t);
void LWZU(ppu_opcode_t);
void LBZ(ppu_opcode_t);
void LBZU(ppu_opcode_t);
void STW(ppu_opcode_t);
void STWU(ppu_opcode_t);
void STB(ppu_opcode_t);
void STBU(ppu_opcode_t);
void LHZ(ppu_opcode_t);
void LHZU(ppu_opcode_t);
void LHA(ppu_opcode_t);
void LHAU(ppu_opcode_t);
void STH(ppu_opcode_t);
void STHU(ppu_opcode_t);
void LMW(ppu_opcode_t);
void STMW(ppu_opcode_t);
void LFS(ppu_opcode_t);
void LFSU(ppu_opcode_t);
void LFD(ppu_opcode_t);
void LFDU(ppu_opcode_t);
void STFS(ppu_opcode_t);
void STFSU(ppu_opcode_t);
void STFD(ppu_opcode_t);
void STFDU(ppu_opcode_t);
void LD(ppu_opcode_t);
void LDU(ppu_opcode_t);
void LWA(ppu_opcode_t);
void STD(ppu_opcode_t);
void STDU(ppu_opcode_t);
void FDIVS(ppu_opcode_t);
void FSUBS(ppu_opcode_t);
void FADDS(ppu_opcode_t);
void FSQRTS(ppu_opcode_t);
void FRES(ppu_opcode_t);
void FMULS(ppu_opcode_t);
void FMADDS(ppu_opcode_t);
void FMSUBS(ppu_opcode_t);
void FNMSUBS(ppu_opcode_t);
void FNMADDS(ppu_opcode_t);
void MTFSB1(ppu_opcode_t);
void MCRFS(ppu_opcode_t);
void MTFSB0(ppu_opcode_t);
void MTFSFI(ppu_opcode_t);
void MFFS(ppu_opcode_t);
void MTFSF(ppu_opcode_t);
void FCMPU(ppu_opcode_t);
void FRSP(ppu_opcode_t);
void FCTIW(ppu_opcode_t);
void FCTIWZ(ppu_opcode_t);
void FDIV(ppu_opcode_t);
void FSUB(ppu_opcode_t);
void FADD(ppu_opcode_t);
void FSQRT(ppu_opcode_t);
void FSEL(ppu_opcode_t);
void FMUL(ppu_opcode_t);
void FRSQRTE(ppu_opcode_t);
void FMSUB(ppu_opcode_t);
void FMADD(ppu_opcode_t);
void FNMSUB(ppu_opcode_t);
void FNMADD(ppu_opcode_t);
void FCMPO(ppu_opcode_t);
void FNEG(ppu_opcode_t);
void FMR(ppu_opcode_t);
void FNABS(ppu_opcode_t);
void FABS(ppu_opcode_t);
void FCTID(ppu_opcode_t);
void FCTIDZ(ppu_opcode_t);
void FCFID(ppu_opcode_t);
};