Path: blob/master/Core/MIPS/LoongArch64/LoongArch64CompLoadStore.cpp
3188 views
// 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/LoongArch64/LoongArch64Jit.h"19#include "Core/MIPS/LoongArch64/LoongArch64RegCache.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 LoongArch64Gen;34using namespace LoongArch64JitConstants;3536void LoongArch64JitBackend::SetScratch1ToSrc1Address(IRReg src1) {37regs_.MapGPR(src1);38#ifdef MASKED_PSP_MEMORY39SLLI_W(SCRATCH1, regs_.R(src1), 2);40SRLI_W(SCRATCH1, SCRATCH1, 2);41ADD_D(SCRATCH1, SCRATCH1, MEMBASEREG);42#else43// Clear the top bits to be safe.44SLLI_D(SCRATCH1, regs_.R(src1), 32);45SRLI_D(SCRATCH1, SCRATCH1, 32);46ADD_D(SCRATCH1, SCRATCH1, MEMBASEREG);47#endif48}4950int32_t LoongArch64JitBackend::AdjustForAddressOffset(LoongArch64Gen::LoongArch64Reg *reg, int32_t constant, int32_t range) {51if (constant < -2048 || constant + range > 2047) {52#ifdef MASKED_PSP_MEMORY53if (constant > 0)54constant &= Memory::MEMVIEW32_MASK;55#endif56// It can't be this negative, must be a constant with top bit set.57if ((constant & 0xC0000000) == 0x80000000) {58LI(SCRATCH2, (uint32_t)constant);59ADD_D(SCRATCH1, *reg, SCRATCH2);60} else {61LI(SCRATCH2, constant);62ADD_D(SCRATCH1, *reg, SCRATCH2);63}64*reg = SCRATCH1;65return 0;66}67return constant;68}6970void LoongArch64JitBackend::CompIR_Load(IRInst inst) {71CONDITIONAL_DISABLE;7273regs_.SpillLockGPR(inst.dest, inst.src1);74LoongArch64Reg addrReg = INVALID_REG;75if (inst.src1 == MIPS_REG_ZERO) {76// This will get changed by AdjustForAddressOffset.77addrReg = MEMBASEREG;78#ifdef MASKED_PSP_MEMORY79inst.constant &= Memory::MEMVIEW32_MASK;80#endif81} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {82addrReg = regs_.MapGPRAsPointer(inst.src1);83} else {84SetScratch1ToSrc1Address(inst.src1);85addrReg = SCRATCH1;86}87// With NOINIT, MapReg won't subtract MEMBASEREG even if dest == src1.88regs_.MapGPR(inst.dest, MIPSMap::NOINIT);89regs_.MarkGPRDirty(inst.dest, true);9091s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);9293// TODO: Safe memory? Or enough to have crash handler + validate?9495switch (inst.op) {96case IROp::Load8:97LD_BU(regs_.R(inst.dest), addrReg, imm);98break;99100case IROp::Load8Ext:101LD_B(regs_.R(inst.dest), addrReg, imm);102break;103104case IROp::Load16:105LD_HU(regs_.R(inst.dest), addrReg, imm);106break;107108case IROp::Load16Ext:109LD_H(regs_.R(inst.dest), addrReg, imm);110break;111112case IROp::Load32:113LD_W(regs_.R(inst.dest), addrReg, imm);114break;115116case IROp::Load32Linked:117if (inst.dest != MIPS_REG_ZERO)118LD_W(regs_.R(inst.dest), addrReg, imm);119regs_.SetGPRImm(IRREG_LLBIT, 1);120break;121122default:123INVALIDOP;124break;125}126}127128void LoongArch64JitBackend::CompIR_LoadShift(IRInst inst) {129CONDITIONAL_DISABLE;130131switch (inst.op) {132case IROp::Load32Left:133case IROp::Load32Right:134// Should not happen if the pass to split is active.135DISABLE;136break;137138default:139INVALIDOP;140break;141}142}143144void LoongArch64JitBackend::CompIR_FLoad(IRInst inst) {145CONDITIONAL_DISABLE;146147LoongArch64Reg addrReg = INVALID_REG;148if (inst.src1 == MIPS_REG_ZERO) {149// This will get changed by AdjustForAddressOffset.150addrReg = MEMBASEREG;151#ifdef MASKED_PSP_MEMORY152inst.constant &= Memory::MEMVIEW32_MASK;153#endif154} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {155addrReg = regs_.MapGPRAsPointer(inst.src1);156} else {157SetScratch1ToSrc1Address(inst.src1);158addrReg = SCRATCH1;159}160161s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);162163// TODO: Safe memory? Or enough to have crash handler + validate?164165switch (inst.op) {166case IROp::LoadFloat:167regs_.MapFPR(inst.dest, MIPSMap::NOINIT);168FLD_S(regs_.F(inst.dest), addrReg, imm);169break;170171default:172INVALIDOP;173break;174}175}176177void LoongArch64JitBackend::CompIR_VecLoad(IRInst inst) {178CONDITIONAL_DISABLE;179180LoongArch64Reg addrReg = INVALID_REG;181if (inst.src1 == MIPS_REG_ZERO) {182// This will get changed by AdjustForAddressOffset.183addrReg = MEMBASEREG;184#ifdef MASKED_PSP_MEMORY185inst.constant &= Memory::MEMVIEW32_MASK;186#endif187} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {188addrReg = regs_.MapGPRAsPointer(inst.src1);189} else {190SetScratch1ToSrc1Address(inst.src1);191addrReg = SCRATCH1;192}193194// We need to be able to address the whole 16 bytes, so offset of 12.195s32 imm = AdjustForAddressOffset(&addrReg, inst.constant, 12);196197// TODO: Safe memory? Or enough to have crash handler + validate?198199switch (inst.op) {200case IROp::LoadVec4:201if (cpu_info.LOONGARCH_LSX) {202regs_.MapVec4(inst.dest, MIPSMap::NOINIT);203VLD(regs_.V(inst.dest), addrReg, imm);204} else {205for (int i = 0; i < 4; ++i) {206// Spilling is okay.207regs_.MapFPR(inst.dest + i, MIPSMap::NOINIT);208FLD_S(regs_.F(inst.dest + i), addrReg, imm + 4 * i);209}210}211break;212213default:214INVALIDOP;215break;216}217}218219void LoongArch64JitBackend::CompIR_Store(IRInst inst) {220CONDITIONAL_DISABLE;221222regs_.SpillLockGPR(inst.src3, inst.src1);223LoongArch64Reg addrReg = INVALID_REG;224if (inst.src1 == MIPS_REG_ZERO) {225// This will get changed by AdjustForAddressOffset.226addrReg = MEMBASEREG;227#ifdef MASKED_PSP_MEMORY228inst.constant &= Memory::MEMVIEW32_MASK;229#endif230} else if ((jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {231addrReg = regs_.MapGPRAsPointer(inst.src1);232} else {233SetScratch1ToSrc1Address(inst.src1);234addrReg = SCRATCH1;235}236LoongArch64Reg valueReg = regs_.TryMapTempImm(inst.src3);237if (valueReg == INVALID_REG)238valueReg = regs_.MapGPR(inst.src3);239240s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);241242// TODO: Safe memory? Or enough to have crash handler + validate?243244switch (inst.op) {245case IROp::Store8:246ST_B(valueReg, addrReg, imm);247break;248249case IROp::Store16:250ST_H(valueReg, addrReg, imm);251break;252253case IROp::Store32:254ST_W(valueReg, addrReg, imm);255break;256257default:258INVALIDOP;259break;260}261}262263void LoongArch64JitBackend::CompIR_CondStore(IRInst inst) {264CONDITIONAL_DISABLE;265if (inst.op != IROp::Store32Conditional)266INVALIDOP;267268regs_.SpillLockGPR(IRREG_LLBIT, inst.src3, inst.src1);269LoongArch64Reg addrReg = INVALID_REG;270if (inst.src1 == MIPS_REG_ZERO) {271// This will get changed by AdjustForAddressOffset.272addrReg = MEMBASEREG;273#ifdef MASKED_PSP_MEMORY274inst.constant &= Memory::MEMVIEW32_MASK;275#endif276} else if ((jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {277addrReg = regs_.MapGPRAsPointer(inst.src1);278} else {279SetScratch1ToSrc1Address(inst.src1);280addrReg = SCRATCH1;281}282regs_.MapGPR(inst.src3, inst.dest == MIPS_REG_ZERO ? MIPSMap::INIT : MIPSMap::DIRTY);283regs_.MapGPR(IRREG_LLBIT);284285s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);286287// TODO: Safe memory? Or enough to have crash handler + validate?288289FixupBranch condFailed = BEQZ(regs_.R(IRREG_LLBIT));290ST_W(regs_.R(inst.src3), addrReg, imm);291292if (inst.dest != MIPS_REG_ZERO) {293LI(regs_.R(inst.dest), 1);294FixupBranch finish = B();295296SetJumpTarget(condFailed);297LI(regs_.R(inst.dest), 0);298SetJumpTarget(finish);299} else {300SetJumpTarget(condFailed);301}302}303304void LoongArch64JitBackend::CompIR_StoreShift(IRInst inst) {305CONDITIONAL_DISABLE;306307switch (inst.op) {308case IROp::Store32Left:309case IROp::Store32Right:310// Should not happen if the pass to split is active.311DISABLE;312break;313314default:315INVALIDOP;316break;317}318}319320void LoongArch64JitBackend::CompIR_FStore(IRInst inst) {321CONDITIONAL_DISABLE;322323LoongArch64Reg addrReg = INVALID_REG;324if (inst.src1 == MIPS_REG_ZERO) {325// This will get changed by AdjustForAddressOffset.326addrReg = MEMBASEREG;327#ifdef MASKED_PSP_MEMORY328inst.constant &= Memory::MEMVIEW32_MASK;329#endif330} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {331addrReg = regs_.MapGPRAsPointer(inst.src1);332} else {333SetScratch1ToSrc1Address(inst.src1);334addrReg = SCRATCH1;335}336337s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);338339// TODO: Safe memory? Or enough to have crash handler + validate?340341switch (inst.op) {342case IROp::StoreFloat:343regs_.MapFPR(inst.src3);344FST_S(regs_.F(inst.src3), addrReg, imm);345break;346347default:348INVALIDOP;349break;350}351}352353void LoongArch64JitBackend::CompIR_VecStore(IRInst inst) {354CONDITIONAL_DISABLE;355356LoongArch64Reg addrReg = INVALID_REG;357if (inst.src1 == MIPS_REG_ZERO) {358// This will get changed by AdjustForAddressOffset.359addrReg = MEMBASEREG;360#ifdef MASKED_PSP_MEMORY361inst.constant &= Memory::MEMVIEW32_MASK;362#endif363} else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) {364addrReg = regs_.MapGPRAsPointer(inst.src1);365} else {366SetScratch1ToSrc1Address(inst.src1);367addrReg = SCRATCH1;368}369370// We need to be able to address the whole 16 bytes, so offset of 12.371s32 imm = AdjustForAddressOffset(&addrReg, inst.constant, 12);372373// TODO: Safe memory? Or enough to have crash handler + validate?374375switch (inst.op) {376case IROp::StoreVec4:377if (cpu_info.LOONGARCH_LSX) {378regs_.MapVec4(inst.src3);379VST(regs_.V(inst.src3), addrReg, imm);380} else {381for (int i = 0; i < 4; ++i) {382// Spilling is okay, though not ideal.383regs_.MapFPR(inst.src3 + i);384FST_S(regs_.F(inst.src3 + i), addrReg, imm + 4 * i);385}386}387break;388389default:390INVALIDOP;391break;392}393}394395} // namespace MIPSComp396397398