#include "Core/MIPS/IR/IRAnalysis.h"
#include <algorithm>
static bool IRReadsFrom(const IRInstMeta &inst, int reg, char type, bool *directly) {
if (inst.m.types[1] == type && inst.src1 == reg) {
if (directly)
*directly = true;
return true;
}
if (inst.m.types[2] == type && inst.src2 == reg) {
if (directly)
*directly = true;
return true;
}
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type && inst.src3 == reg) {
if (directly)
*directly = true;
return true;
}
if (directly)
*directly = false;
if ((inst.m.flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0)
return true;
return false;
}
bool IRReadsFromFPR(const IRInstMeta &inst, int reg, bool *directly) {
if (IRReadsFrom(inst, reg, 'F', directly))
return true;
if (inst.m.types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4)
return true;
if (inst.m.types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2)
return true;
if (inst.m.types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4)
return true;
if (inst.m.types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2)
return true;
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (inst.m.types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4)
return true;
if (inst.m.types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2)
return true;
}
return false;
}
static int IRReadsFromList(const IRInstMeta &inst, IRReg regs[4], char type) {
int c = 0;
if (inst.m.types[1] == type)
regs[c++] = inst.src1;
if (inst.m.types[2] == type)
regs[c++] = inst.src2;
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type)
regs[c++] = inst.src3;
if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)
return -1;
if (inst.op == IROp::Breakpoint || inst.op == IROp::MemoryCheck)
return -1;
return c;
}
bool IRReadsFromGPR(const IRInstMeta &inst, int reg, bool *directly) {
return IRReadsFrom(inst, reg, 'G', directly);
}
int IRDestGPR(const IRInstMeta &inst) {
if ((inst.m.flags & IRFLAG_SRC3) == 0 && inst.m.types[0] == 'G') {
return inst.dest;
}
return -1;
}
bool IRWritesToGPR(const IRInstMeta &inst, int reg) {
return IRDestGPR(inst) == reg;
}
bool IRWritesToFPR(const IRInstMeta &inst, int reg) {
if ((inst.m.flags & IRFLAG_SRC3) != 0)
return false;
if (inst.m.types[0] == 'F' && reg == inst.dest)
return true;
if (inst.m.types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4)
return true;
if (inst.m.types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2)
return true;
return false;
}
int IRDestFPRs(const IRInstMeta &inst, IRReg regs[4]) {
if ((inst.m.flags & IRFLAG_SRC3) != 0)
return 0;
if (inst.m.types[0] == 'F') {
regs[0] = inst.dest;
return 1;
}
if (inst.m.types[0] == 'V') {
for (int i = 0; i < 4; ++i)
regs[i] = inst.dest + i;
return 4;
}
if (inst.m.types[0] == '2') {
for (int i = 0; i < 2; ++i)
regs[i] = inst.dest + i;
return 2;
}
return 0;
}
int IRReadsFromGPRs(const IRInstMeta &inst, IRReg regs[4]) {
return IRReadsFromList(inst, regs, 'G');
}
int IRReadsFromFPRs(const IRInstMeta &inst, IRReg regs[16]) {
int c = IRReadsFromList(inst, regs, 'F');
if (c != 0)
return c;
if (inst.m.types[1] == 'V' || inst.m.types[1] == '2') {
for (int i = 0; i < (inst.m.types[1] == 'V' ? 4 : 2); ++i)
regs[c++] = inst.src1 + i;
}
if (inst.m.types[2] == 'V' || inst.m.types[2] == '2') {
for (int i = 0; i < (inst.m.types[2] == 'V' ? 4 : 2); ++i)
regs[c++] = inst.src2 + i;
}
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (inst.m.types[0] == 'V' || inst.m.types[0] == '2') {
for (int i = 0; i < (inst.m.types[0] == 'V' ? 4 : 2); ++i)
regs[c++] = inst.src3 + i;
}
}
return c;
}
IRUsage IRNextGPRUsage(int gpr, const IRSituation &info) {
if (gpr >= 32)
return IRUsage::UNKNOWN;
int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
for (int i = 0; i < count; ++i) {
const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]);
if (IRReadsFromGPR(inst, gpr))
return IRUsage::READ;
if (IRDestGPR(inst) == gpr)
return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;
}
return IRUsage::UNUSED;
}
IRUsage IRNextFPRUsage(int fpr, const IRSituation &info) {
if (fpr < 0 || (fpr >= 160 && fpr < 192) || fpr >= 208)
return IRUsage::UNKNOWN;
int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
for (int i = 0; i < count; ++i) {
const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]);
if (IRReadsFromFPR(inst, fpr)) {
if (inst.op == IROp::Vec4Shuffle && inst.src2 == 0 && inst.dest == inst.src1)
return inst.src1 == fpr ? IRUsage::READ : IRUsage::CLOBBERED;
if (fpr < IRVTEMP_PFX_S || (GetIRMeta(inst.op)->flags & IRFLAG_EXIT) == 0)
return IRUsage::READ;
}
if (IRWritesToFPR(inst, fpr)) {
return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;
}
}
if (fpr >= IRVTEMP_PFX_S && count == info.numInstructions - info.currentIndex)
return IRUsage::CLOBBERED;
return IRUsage::UNUSED;
}