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/RiscV/RiscVCompLoadStore.cpp
Views: 1401
// Copyright (c) 2023- 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/MemMap.h"18#include "Core/MIPS/RiscV/RiscVJit.h"19#include "Core/MIPS/RiscV/RiscVRegCache.h"2021// This file contains compilation for load/store instructions.22//23// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.24// Currently known non working ones should have DISABLE. No flags because that's in IR already.2526// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }27#define CONDITIONAL_DISABLE {}28#define DISABLE { CompIR_Generic(inst); return; }29#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }3031namespace MIPSComp {3233using namespace RiscVGen;34using namespace RiscVJitConstants;3536void RiscVJitBackend::SetScratch1ToSrc1Address(IRReg src1) {37regs_.MapGPR(src1);38#ifdef MASKED_PSP_MEMORY39SLLIW(SCRATCH1, regs_.R(src1), 2);40SRLIW(SCRATCH1, SCRATCH1, 2);41ADD(SCRATCH1, SCRATCH1, MEMBASEREG);42#else43// Clear the top bits to be safe.44if (cpu_info.RiscV_Zba) {45ADD_UW(SCRATCH1, regs_.R(src1), MEMBASEREG);46} else {47_assert_(XLEN == 64);48SLLI(SCRATCH1, regs_.R(src1), 32);49SRLI(SCRATCH1, SCRATCH1, 32);50ADD(SCRATCH1, SCRATCH1, MEMBASEREG);51}52#endif53}5455int32_t RiscVJitBackend::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t constant, int32_t range) {56if (constant < -2048 || constant + range > 2047) {57#ifdef MASKED_PSP_MEMORY58if (constant > 0)59constant &= Memory::MEMVIEW32_MASK;60#endif61// It can't be this negative, must be a constant with top bit set.62if ((constant & 0xC0000000) == 0x80000000) {63if (cpu_info.RiscV_Zba) {64LI(SCRATCH2, constant);65ADD_UW(SCRATCH1, SCRATCH2, *reg);66} else {67LI(SCRATCH2, (uint32_t)constant);68ADD(SCRATCH1, *reg, SCRATCH2);69}70} else {71LI(SCRATCH2, constant);72ADD(SCRATCH1, *reg, SCRATCH2);73}74*reg = SCRATCH1;75return 0;76}77return constant;78}7980void RiscVJitBackend::CompIR_Load(IRInst inst) {81CONDITIONAL_DISABLE;8283regs_.SpillLockGPR(inst.dest, inst.src1);84RiscVReg addrReg = INVALID_REG;85if (inst.src1 == MIPS_REG_ZERO) {86// This will get changed by AdjustForAddressOffset.87addrReg = MEMBASEREG;88#ifdef MASKED_PSP_MEMORY89inst.constant &= Memory::MEMVIEW32_MASK;90#endif91} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {92addrReg = regs_.MapGPRAsPointer(inst.src1);93} else {94SetScratch1ToSrc1Address(inst.src1);95addrReg = SCRATCH1;96}97// With NOINIT, MapReg won't subtract MEMBASEREG even if dest == src1.98regs_.MapGPR(inst.dest, MIPSMap::NOINIT);99regs_.MarkGPRDirty(inst.dest, true);100101s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);102103// TODO: Safe memory? Or enough to have crash handler + validate?104105switch (inst.op) {106case IROp::Load8:107LBU(regs_.R(inst.dest), addrReg, imm);108break;109110case IROp::Load8Ext:111LB(regs_.R(inst.dest), addrReg, imm);112break;113114case IROp::Load16:115LHU(regs_.R(inst.dest), addrReg, imm);116break;117118case IROp::Load16Ext:119LH(regs_.R(inst.dest), addrReg, imm);120break;121122case IROp::Load32:123LW(regs_.R(inst.dest), addrReg, imm);124break;125126case IROp::Load32Linked:127if (inst.dest != MIPS_REG_ZERO)128LW(regs_.R(inst.dest), addrReg, imm);129regs_.SetGPRImm(IRREG_LLBIT, 1);130break;131132default:133INVALIDOP;134break;135}136}137138void RiscVJitBackend::CompIR_LoadShift(IRInst inst) {139CONDITIONAL_DISABLE;140141switch (inst.op) {142case IROp::Load32Left:143case IROp::Load32Right:144// Should not happen if the pass to split is active.145DISABLE;146break;147148default:149INVALIDOP;150break;151}152}153154void RiscVJitBackend::CompIR_FLoad(IRInst inst) {155CONDITIONAL_DISABLE;156157RiscVReg addrReg = INVALID_REG;158if (inst.src1 == MIPS_REG_ZERO) {159// This will get changed by AdjustForAddressOffset.160addrReg = MEMBASEREG;161#ifdef MASKED_PSP_MEMORY162inst.constant &= Memory::MEMVIEW32_MASK;163#endif164} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {165addrReg = regs_.MapGPRAsPointer(inst.src1);166} else {167SetScratch1ToSrc1Address(inst.src1);168addrReg = SCRATCH1;169}170171s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);172173// TODO: Safe memory? Or enough to have crash handler + validate?174175switch (inst.op) {176case IROp::LoadFloat:177regs_.MapFPR(inst.dest, MIPSMap::NOINIT);178FL(32, regs_.F(inst.dest), addrReg, imm);179break;180181default:182INVALIDOP;183break;184}185}186187void RiscVJitBackend::CompIR_VecLoad(IRInst inst) {188CONDITIONAL_DISABLE;189190RiscVReg addrReg = INVALID_REG;191if (inst.src1 == MIPS_REG_ZERO) {192// This will get changed by AdjustForAddressOffset.193addrReg = MEMBASEREG;194#ifdef MASKED_PSP_MEMORY195inst.constant &= Memory::MEMVIEW32_MASK;196#endif197} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {198addrReg = regs_.MapGPRAsPointer(inst.src1);199} else {200SetScratch1ToSrc1Address(inst.src1);201addrReg = SCRATCH1;202}203204// We need to be able to address the whole 16 bytes, so offset of 12.205s32 imm = AdjustForAddressOffset(&addrReg, inst.constant, 12);206207// TODO: Safe memory? Or enough to have crash handler + validate?208209switch (inst.op) {210case IROp::LoadVec4:211for (int i = 0; i < 4; ++i) {212// Spilling is okay.213regs_.MapFPR(inst.dest + i, MIPSMap::NOINIT);214FL(32, regs_.F(inst.dest + i), addrReg, imm + 4 * i);215}216break;217218default:219INVALIDOP;220break;221}222}223224void RiscVJitBackend::CompIR_Store(IRInst inst) {225CONDITIONAL_DISABLE;226227regs_.SpillLockGPR(inst.src3, inst.src1);228RiscVReg addrReg = INVALID_REG;229if (inst.src1 == MIPS_REG_ZERO) {230// This will get changed by AdjustForAddressOffset.231addrReg = MEMBASEREG;232#ifdef MASKED_PSP_MEMORY233inst.constant &= Memory::MEMVIEW32_MASK;234#endif235} else if ((jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {236addrReg = regs_.MapGPRAsPointer(inst.src1);237} else {238SetScratch1ToSrc1Address(inst.src1);239addrReg = SCRATCH1;240}241RiscVReg valueReg = regs_.TryMapTempImm(inst.src3);242if (valueReg == INVALID_REG)243valueReg = regs_.MapGPR(inst.src3);244245s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);246247// TODO: Safe memory? Or enough to have crash handler + validate?248249switch (inst.op) {250case IROp::Store8:251SB(valueReg, addrReg, imm);252break;253254case IROp::Store16:255SH(valueReg, addrReg, imm);256break;257258case IROp::Store32:259SW(valueReg, addrReg, imm);260break;261262default:263INVALIDOP;264break;265}266}267268void RiscVJitBackend::CompIR_CondStore(IRInst inst) {269CONDITIONAL_DISABLE;270if (inst.op != IROp::Store32Conditional)271INVALIDOP;272273regs_.SpillLockGPR(IRREG_LLBIT, inst.src3, inst.src1);274RiscVReg addrReg = INVALID_REG;275if (inst.src1 == MIPS_REG_ZERO) {276// This will get changed by AdjustForAddressOffset.277addrReg = MEMBASEREG;278#ifdef MASKED_PSP_MEMORY279inst.constant &= Memory::MEMVIEW32_MASK;280#endif281} else if ((jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {282addrReg = regs_.MapGPRAsPointer(inst.src1);283} else {284SetScratch1ToSrc1Address(inst.src1);285addrReg = SCRATCH1;286}287regs_.MapGPR(inst.src3, inst.dest == MIPS_REG_ZERO ? MIPSMap::INIT : MIPSMap::DIRTY);288regs_.MapGPR(IRREG_LLBIT);289290s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);291292// TODO: Safe memory? Or enough to have crash handler + validate?293294FixupBranch condFailed = BEQ(regs_.R(IRREG_LLBIT), R_ZERO);295SW(regs_.R(inst.src3), addrReg, imm);296297if (inst.dest != MIPS_REG_ZERO) {298LI(regs_.R(inst.dest), 1);299FixupBranch finish = J();300301SetJumpTarget(condFailed);302LI(regs_.R(inst.dest), 0);303SetJumpTarget(finish);304} else {305SetJumpTarget(condFailed);306}307}308309void RiscVJitBackend::CompIR_StoreShift(IRInst inst) {310CONDITIONAL_DISABLE;311312switch (inst.op) {313case IROp::Store32Left:314case IROp::Store32Right:315// Should not happen if the pass to split is active.316DISABLE;317break;318319default:320INVALIDOP;321break;322}323}324325void RiscVJitBackend::CompIR_FStore(IRInst inst) {326CONDITIONAL_DISABLE;327328RiscVReg addrReg = INVALID_REG;329if (inst.src1 == MIPS_REG_ZERO) {330// This will get changed by AdjustForAddressOffset.331addrReg = MEMBASEREG;332#ifdef MASKED_PSP_MEMORY333inst.constant &= Memory::MEMVIEW32_MASK;334#endif335} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {336addrReg = regs_.MapGPRAsPointer(inst.src1);337} else {338SetScratch1ToSrc1Address(inst.src1);339addrReg = SCRATCH1;340}341342s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);343344// TODO: Safe memory? Or enough to have crash handler + validate?345346switch (inst.op) {347case IROp::StoreFloat:348regs_.MapFPR(inst.src3);349FS(32, regs_.F(inst.src3), addrReg, imm);350break;351352default:353INVALIDOP;354break;355}356}357358void RiscVJitBackend::CompIR_VecStore(IRInst inst) {359CONDITIONAL_DISABLE;360361RiscVReg addrReg = INVALID_REG;362if (inst.src1 == MIPS_REG_ZERO) {363// This will get changed by AdjustForAddressOffset.364addrReg = MEMBASEREG;365#ifdef MASKED_PSP_MEMORY366inst.constant &= Memory::MEMVIEW32_MASK;367#endif368} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {369addrReg = regs_.MapGPRAsPointer(inst.src1);370} else {371SetScratch1ToSrc1Address(inst.src1);372addrReg = SCRATCH1;373}374375// We need to be able to address the whole 16 bytes, so offset of 12.376s32 imm = AdjustForAddressOffset(&addrReg, inst.constant, 12);377378// TODO: Safe memory? Or enough to have crash handler + validate?379380switch (inst.op) {381case IROp::StoreVec4:382for (int i = 0; i < 4; ++i) {383// Spilling is okay, though not ideal.384regs_.MapFPR(inst.src3 + i);385FS(32, regs_.F(inst.src3 + i), addrReg, imm + 4 * i);386}387break;388389default:390INVALIDOP;391break;392}393}394395} // namespace MIPSComp396397398