CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/MIPS/IR/IRAnalysis.cpp
Views: 1401
// Copyright (c) 2016- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Core/MIPS/IR/IRAnalysis.h"1819// For std::min20#include <algorithm>212223static bool IRReadsFrom(const IRInstMeta &inst, int reg, char type, bool *directly) {24if (inst.m.types[1] == type && inst.src1 == reg) {25if (directly)26*directly = true;27return true;28}29if (inst.m.types[2] == type && inst.src2 == reg) {30if (directly)31*directly = true;32return true;33}34if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type && inst.src3 == reg) {35if (directly)36*directly = true;37return true;38}3940if (directly)41*directly = false;42if ((inst.m.flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0)43return true;44return false;45}4647bool IRReadsFromFPR(const IRInstMeta &inst, int reg, bool *directly) {48if (IRReadsFrom(inst, reg, 'F', directly))49return true;5051// We also need to check V and 2. Indirect reads already checked, don't check again.52if (inst.m.types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4)53return true;54if (inst.m.types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2)55return true;56if (inst.m.types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4)57return true;58if (inst.m.types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2)59return true;60if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {61if (inst.m.types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4)62return true;63if (inst.m.types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2)64return true;65}66return false;67}6869static int IRReadsFromList(const IRInstMeta &inst, IRReg regs[4], char type) {70int c = 0;7172if (inst.m.types[1] == type)73regs[c++] = inst.src1;74if (inst.m.types[2] == type)75regs[c++] = inst.src2;76if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type)77regs[c++] = inst.src3;7879if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)80return -1;81if (inst.op == IROp::Breakpoint || inst.op == IROp::MemoryCheck)82return -1;8384return c;85}8687bool IRReadsFromGPR(const IRInstMeta &inst, int reg, bool *directly) {88return IRReadsFrom(inst, reg, 'G', directly);89}9091int IRDestGPR(const IRInstMeta &inst) {92if ((inst.m.flags & IRFLAG_SRC3) == 0 && inst.m.types[0] == 'G') {93return inst.dest;94}95return -1;96}9798bool IRWritesToGPR(const IRInstMeta &inst, int reg) {99return IRDestGPR(inst) == reg;100}101102bool IRWritesToFPR(const IRInstMeta &inst, int reg) {103// Doesn't write to anything.104if ((inst.m.flags & IRFLAG_SRC3) != 0)105return false;106107if (inst.m.types[0] == 'F' && reg == inst.dest)108return true;109if (inst.m.types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4)110return true;111if (inst.m.types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2)112return true;113return false;114}115116int IRDestFPRs(const IRInstMeta &inst, IRReg regs[4]) {117// Doesn't write to anything.118if ((inst.m.flags & IRFLAG_SRC3) != 0)119return 0;120121if (inst.m.types[0] == 'F') {122regs[0] = inst.dest;123return 1;124}125if (inst.m.types[0] == 'V') {126for (int i = 0; i < 4; ++i)127regs[i] = inst.dest + i;128return 4;129}130if (inst.m.types[0] == '2') {131for (int i = 0; i < 2; ++i)132regs[i] = inst.dest + i;133return 2;134}135return 0;136}137138int IRReadsFromGPRs(const IRInstMeta &inst, IRReg regs[4]) {139return IRReadsFromList(inst, regs, 'G');140}141142int IRReadsFromFPRs(const IRInstMeta &inst, IRReg regs[16]) {143int c = IRReadsFromList(inst, regs, 'F');144if (c != 0)145return c;146147// We also need to check V and 2. Indirect reads already checked, don't check again.148if (inst.m.types[1] == 'V' || inst.m.types[1] == '2') {149for (int i = 0; i < (inst.m.types[1] == 'V' ? 4 : 2); ++i)150regs[c++] = inst.src1 + i;151}152if (inst.m.types[2] == 'V' || inst.m.types[2] == '2') {153for (int i = 0; i < (inst.m.types[2] == 'V' ? 4 : 2); ++i)154regs[c++] = inst.src2 + i;155}156if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {157if (inst.m.types[0] == 'V' || inst.m.types[0] == '2') {158for (int i = 0; i < (inst.m.types[0] == 'V' ? 4 : 2); ++i)159regs[c++] = inst.src3 + i;160}161}162return c;163}164165IRUsage IRNextGPRUsage(int gpr, const IRSituation &info) {166// Exclude any "special" regs from this logic for now.167if (gpr >= 32)168return IRUsage::UNKNOWN;169170int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);171for (int i = 0; i < count; ++i) {172const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]);173if (IRReadsFromGPR(inst, gpr))174return IRUsage::READ;175// We say WRITE when the current instruction writes. It's not useful for spilling.176if (IRDestGPR(inst) == gpr)177return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;178}179180return IRUsage::UNUSED;181}182183IRUsage IRNextFPRUsage(int fpr, const IRSituation &info) {184// Let's only pay attention to standard FP regs and temps.185// See MIPS.h for these offsets.186if (fpr < 0 || (fpr >= 160 && fpr < 192) || fpr >= 208)187return IRUsage::UNKNOWN;188189int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);190for (int i = 0; i < count; ++i) {191const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]);192193if (IRReadsFromFPR(inst, fpr)) {194// Special case a broadcast that clobbers it.195if (inst.op == IROp::Vec4Shuffle && inst.src2 == 0 && inst.dest == inst.src1)196return inst.src1 == fpr ? IRUsage::READ : IRUsage::CLOBBERED;197198// If this is an exit reading a temp, ignore it.199if (fpr < IRVTEMP_PFX_S || (GetIRMeta(inst.op)->flags & IRFLAG_EXIT) == 0)200return IRUsage::READ;201}202// We say WRITE when the current instruction writes. It's not useful for spilling.203if (IRWritesToFPR(inst, fpr)) {204return i == 0 ? IRUsage::WRITE : IRUsage::CLOBBERED;205}206}207208// This means we only had exits and hit the end.209if (fpr >= IRVTEMP_PFX_S && count == info.numInstructions - info.currentIndex)210return IRUsage::CLOBBERED;211212return IRUsage::UNUSED;213}214215216