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/IRCompALU.cpp
Views: 1401
// Copyright (c) 2012- 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 <algorithm>1819#include "Core/MIPS/MIPS.h"20#include "Core/MIPS/MIPSCodeUtils.h"21#include "Core/MIPS/IR/IRFrontend.h"22#include "Common/CPUDetect.h"2324#define _RS MIPS_GET_RS(op)25#define _RT MIPS_GET_RT(op)26#define _RD MIPS_GET_RD(op)27#define _FS MIPS_GET_FS(op)28#define _FT MIPS_GET_FT(op)29#define _FD MIPS_GET_FD(op)30#define _SA MIPS_GET_SA(op)31#define _POS ((op>> 6) & 0x1F)32#define _SIZE ((op>>11) & 0x1F)33#define _IMM16 (signed short)(op & 0xFFFF)34#define _IMM26 (op & 0x03FFFFFF)3536// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.37// Currently known non working ones should have DISABLE.3839// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }40#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }41#define DISABLE { Comp_Generic(op); return; }42#define INVALIDOP { Comp_Generic(op); return; }4344namespace MIPSComp {4546void IRFrontend::Comp_IType(MIPSOpcode op) {47CONDITIONAL_DISABLE(ALU_IMM);4849u32 uimm = (u16)_IMM16;50s32 simm = SignExtend16ToS32(op);51u32 suimm = SignExtend16ToU32(op);5253MIPSGPReg rt = _RT;54MIPSGPReg rs = _RS;5556// noop, won't write to ZERO.57if (rt == MIPS_REG_ZERO)58return;5960switch (op >> 26) {61case 8: // same as addiu?62case 9: // R(rt) = R(rs) + simm; break; //addiu63ir.Write(IROp::AddConst, rt, rs, ir.AddConstant(simm));64break;6566case 12: ir.Write(IROp::AndConst, rt, rs, ir.AddConstant(uimm)); break;67case 13: ir.Write(IROp::OrConst, rt, rs, ir.AddConstant(uimm)); break;68case 14: ir.Write(IROp::XorConst, rt, rs, ir.AddConstant(uimm)); break;6970case 10: // R(rt) = (s32)R(rs) < simm; break; //slti71ir.Write(IROp::SltConst, rt, rs, ir.AddConstant(simm));72break;7374case 11: // R(rt) = R(rs) < suimm; break; //sltiu75ir.Write(IROp::SltUConst, rt, rs, ir.AddConstant(suimm));76break;7778case 15: // R(rt) = uimm << 16; //lui79ir.WriteSetConstant(rt, uimm << 16);80break;8182default:83INVALIDOP;84break;85}86}8788void IRFrontend::Comp_RType2(MIPSOpcode op) {89CONDITIONAL_DISABLE(ALU_BIT);9091MIPSGPReg rs = _RS;92MIPSGPReg rd = _RD;9394// Don't change $zr.95if (rd == MIPS_REG_ZERO)96return;9798switch (op & 63) {99case 22: //clz100ir.Write(IROp::Clz, rd, rs);101break;102case 23: //clo103ir.Write(IROp::Not, IRTEMP_0, rs);104ir.Write(IROp::Clz, rd, IRTEMP_0);105break;106default:107INVALIDOP;108break;109}110}111112void IRFrontend::Comp_RType3(MIPSOpcode op) {113CONDITIONAL_DISABLE(ALU);114115MIPSGPReg rt = _RT;116MIPSGPReg rs = _RS;117MIPSGPReg rd = _RD;118119// noop, won't write to ZERO.120if (rd == MIPS_REG_ZERO)121return;122123switch (op & 63) {124case 10: //if (!R(rt)) R(rd) = R(rs); break; //movz125ir.Write(IROp::MovZ, rd, rt, rs);126break;127case 11:// if (R(rt)) R(rd) = R(rs); break; //movn128ir.Write(IROp::MovNZ, rd, rt, rs);129break;130131case 32: //R(rd) = R(rs) + R(rt); break; //add132case 33: //R(rd) = R(rs) + R(rt); break; //addu133ir.Write(IROp::Add, rd, rs, rt);134break;135136case 34: //R(rd) = R(rs) - R(rt); break; //sub137case 35: //R(rd) = R(rs) - R(rt); break; //subu138ir.Write(IROp::Sub, rd, rs, rt);139break;140141case 36: //R(rd) = R(rs) & R(rt); break; //and142ir.Write(IROp::And, rd, rs, rt);143break;144case 37: //R(rd) = R(rs) | R(rt); break; //or145ir.Write(IROp::Or, rd, rs, rt);146break;147case 38: //R(rd) = R(rs) ^ R(rt); break; //xor/eor148ir.Write(IROp::Xor, rd, rs, rt);149break;150151case 39: // R(rd) = ~(R(rs) | R(rt)); break; //nor152if (rs == 0) {153ir.Write(IROp::Not, rd, rt);154} else if (rt == 0) {155ir.Write(IROp::Not, rd, rs);156} else {157ir.Write(IROp::Or, IRTEMP_0, rs, rt);158ir.Write(IROp::Not, rd, IRTEMP_0);159}160break;161162case 42: //R(rd) = (int)R(rs) < (int)R(rt); break; //slt163ir.Write(IROp::Slt, rd, rs, rt);164break;165166case 43: //R(rd) = R(rs) < R(rt); break; //sltu167ir.Write(IROp::SltU, rd, rs, rt);168break;169170case 44: //R(rd) = max(R(rs), R(rt); break; //max171ir.Write(IROp::Max, rd, rs, rt);172break;173174case 45: //R(rd) = min(R(rs), R(rt)); break; //min175ir.Write(IROp::Min, rd, rs, rt);176break;177178default:179INVALIDOP;180break;181}182}183184void IRFrontend::CompShiftImm(MIPSOpcode op, IROp shiftOpImm, int sa) {185MIPSGPReg rd = _RD;186MIPSGPReg rt = _RT;187ir.Write(shiftOpImm, rd, rt, sa);188}189190void IRFrontend::CompShiftVar(MIPSOpcode op, IROp shiftOp) {191MIPSGPReg rd = _RD;192MIPSGPReg rt = _RT;193MIPSGPReg rs = _RS;194195if (opts.optimizeForInterpreter) {196// The interpreter already masks where needed, don't need to generate extra ops.197ir.Write(shiftOp, rd, rt, rs);198} else {199ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(31));200ir.Write(shiftOp, rd, rt, IRTEMP_0);201}202}203204void IRFrontend::Comp_ShiftType(MIPSOpcode op) {205CONDITIONAL_DISABLE(ALU);206MIPSGPReg rs = _RS;207MIPSGPReg rd = _RD;208int sa = _SA;209210// noop, won't write to ZERO.211if (rd == MIPS_REG_ZERO)212return;213214// WARNING: srl/rotr and srlv/rotrv share encodings (differentiated using unused bits.)215switch (op & 0x3f) {216case 0: CompShiftImm(op, IROp::ShlImm, sa); break; //sll217case 2: CompShiftImm(op, (rs == 1 ? IROp::RorImm : IROp::ShrImm), sa); break; //srl218case 3: CompShiftImm(op, IROp::SarImm, sa); break; //sra219case 4: CompShiftVar(op, IROp::Shl); break; //sllv220case 6: CompShiftVar(op, (sa == 1 ? IROp::Ror : IROp::Shr)); break; //srlv221case 7: CompShiftVar(op, IROp::Sar); break; //srav222223default:224INVALIDOP;225break;226}227}228229void IRFrontend::Comp_Special3(MIPSOpcode op) {230CONDITIONAL_DISABLE(ALU_BIT);231MIPSGPReg rs = _RS;232MIPSGPReg rt = _RT;233234int pos = _POS;235int size = _SIZE + 1;236u32 mask = 0xFFFFFFFFUL >> (32 - size);237238// Don't change $zr.239if (rt == MIPS_REG_ZERO)240return;241242switch (op & 0x3f) {243case 0x0: // ext244if (pos != 0) {245ir.Write(IROp::ShrImm, rt, rs, pos);246ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(mask));247} else {248ir.Write(IROp::AndConst, rt, rs, ir.AddConstant(mask));249}250break;251252case 0x4: //ins253{254// TODO: Might be good to support natively in the interpreter. Though, would have to255// abuse a register as a constant256u32 sourcemask = mask >> pos;257u32 destmask = ~(sourcemask << pos);258259if (size != 32) {260// Need to use the sourcemask.261ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(sourcemask));262if (pos != 0) {263ir.Write(IROp::ShlImm, IRTEMP_0, IRTEMP_0, pos);264}265} else {266// If the shl takes care of the sourcemask, don't need to and.267if (pos != 0) {268ir.Write(IROp::ShlImm, IRTEMP_0, rs, pos);269} else {270ir.Write(IROp::Mov, IRTEMP_0, rs);271}272}273ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(destmask));274ir.Write(IROp::Or, rt, rt, IRTEMP_0);275}276break;277278default:279INVALIDOP;280break;281}282}283284285void IRFrontend::Comp_Allegrex(MIPSOpcode op) {286CONDITIONAL_DISABLE(ALU_BIT);287MIPSGPReg rt = _RT;288MIPSGPReg rd = _RD;289290// Don't change $zr.291if (rd == MIPS_REG_ZERO)292return;293294switch ((op >> 6) & 31) {295case 16: // seb // R(rd) = SignExtend8ToU32(R(rt));296ir.Write(IROp::Ext8to32, rd, rt);297break;298299case 24: // seh300ir.Write(IROp::Ext16to32, rd, rt);301break;302303case 20: // bitrev304ir.Write(IROp::ReverseBits, rd, rt);305break;306307default:308INVALIDOP;309return;310}311}312313void IRFrontend::Comp_Allegrex2(MIPSOpcode op) {314CONDITIONAL_DISABLE(ALU_BIT);315MIPSGPReg rt = _RT;316MIPSGPReg rd = _RD;317318// Don't change $zr.319if (rd == MIPS_REG_ZERO)320return;321322switch (op & 0x3ff) {323case 0xA0: //wsbh324ir.Write(IROp::BSwap16, rd, rt);325break;326case 0xE0: //wsbw327ir.Write(IROp::BSwap32, rd, rt);328break;329default:330INVALIDOP;331break;332}333}334335void IRFrontend::Comp_MulDivType(MIPSOpcode op) {336CONDITIONAL_DISABLE(MULDIV);337MIPSGPReg rt = _RT;338MIPSGPReg rs = _RS;339MIPSGPReg rd = _RD;340341switch (op & 63) {342case 16: // R(rd) = HI; //mfhi343if (rd != MIPS_REG_ZERO) {344ir.Write(IROp::MfHi, rd);345}346break;347348case 17: // HI = R(rs); //mthi349ir.Write(IROp::MtHi, 0, rs);350break;351352case 18: // R(rd) = LO; break; //mflo353if (rd != MIPS_REG_ZERO) {354ir.Write(IROp::MfLo, rd);355}356break;357358case 19: // LO = R(rs); break; //mtlo359ir.Write(IROp::MtLo, 0, rs);360break;361362case 24: //mult (the most popular one). lo,hi = signed mul (rs * rt)363ir.Write(IROp::Mult, 0, rs, rt);364break;365366case 25: //multu (2nd) lo,hi = unsigned mul (rs * rt)367ir.Write(IROp::MultU, 0, rs, rt);368break;369370case 26: //div371ir.Write(IROp::Div, 0, rs, rt);372break;373374case 27: //divu375ir.Write(IROp::DivU, 0, rs, rt);376break;377378case 28: //madd379ir.Write(IROp::Madd, 0, rs, rt);380break;381382case 29: //maddu383ir.Write(IROp::MaddU, 0, rs, rt);384break;385386case 46: // msub387ir.Write(IROp::Msub, 0, rs, rt);388break;389390case 47: // msubu391ir.Write(IROp::MsubU, 0, rs, rt);392break;393394default:395INVALIDOP;396}397}398399}400401402