Path: blob/master/Core/MIPS/LoongArch64/LoongArch64CompALU.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 "Common/CPUDetect.h"18#include "Core/MemMap.h"19#include "Core/MIPS/LoongArch64/LoongArch64Jit.h"20#include "Core/MIPS/LoongArch64/LoongArch64RegCache.h"2122// This file contains compilation for integer / arithmetic / logic related instructions.23//24// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.25// Currently known non working ones should have DISABLE. No flags because that's in IR already.2627// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }28#define CONDITIONAL_DISABLE {}29#define DISABLE { CompIR_Generic(inst); return; }30#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }3132namespace MIPSComp {3334using namespace LoongArch64Gen;35using namespace LoongArch64JitConstants;3637void LoongArch64JitBackend::CompIR_Arith(IRInst inst) {38CONDITIONAL_DISABLE;3940bool allowPtrMath = true;41#ifdef MASKED_PSP_MEMORY42// Since we modify it, we can't safely.43allowPtrMath = false;44#endif4546// LoongArch64 only adds signed immediates, so rewrite a small enough subtract to an add.47// We use -2047 and 2048 here because the range swaps.48if (inst.op == IROp::SubConst && (int32_t)inst.constant >= -2047 && (int32_t)inst.constant <= 2048) {49inst.op = IROp::AddConst;50inst.constant = (uint32_t)-(int32_t)inst.constant;51}5253switch (inst.op) {54case IROp::Add:55regs_.Map(inst);56ADD_W(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));57regs_.MarkGPRDirty(inst.dest, true);58break;5960case IROp::Sub:61regs_.Map(inst);62SUB_W(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));63regs_.MarkGPRDirty(inst.dest, true);64break;6566case IROp::AddConst:67if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) {68// Typical of stack pointer updates.69if (regs_.IsGPRMappedAsPointer(inst.dest) && inst.dest == inst.src1 && allowPtrMath) {70regs_.MarkGPRAsPointerDirty(inst.dest);71ADDI_D(regs_.RPtr(inst.dest), regs_.RPtr(inst.dest), inst.constant);72} else {73regs_.Map(inst);74ADDI_W(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant);75regs_.MarkGPRDirty(inst.dest, true);76}77} else {78regs_.Map(inst);79LI(SCRATCH1, (int32_t)inst.constant);80ADD_W(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1);81regs_.MarkGPRDirty(inst.dest, true);82}83break;8485case IROp::SubConst:86regs_.Map(inst);87LI(SCRATCH1, (int32_t)inst.constant);88SUB_W(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1);89regs_.MarkGPRDirty(inst.dest, true);90break;9192case IROp::Neg:93regs_.Map(inst);94SUB_W(regs_.R(inst.dest), R_ZERO, regs_.R(inst.src1));95regs_.MarkGPRDirty(inst.dest, true);96break;9798default:99INVALIDOP;100break;101}102}103104void LoongArch64JitBackend::CompIR_Logic(IRInst inst) {105CONDITIONAL_DISABLE;106107bool resultNormalized = false;108switch (inst.op) {109case IROp::And:110if (inst.src1 != inst.src2) {111regs_.Map(inst);112AND(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));113} else if (inst.src1 != inst.dest) {114regs_.Map(inst);115MOVE(regs_.R(inst.dest), regs_.R(inst.src1));116regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));117}118break;119120case IROp::Or:121if (inst.src1 != inst.src2) {122// If both were normalized before, the result is normalized.123resultNormalized = regs_.IsNormalized32(inst.src1) && regs_.IsNormalized32(inst.src2);124regs_.Map(inst);125OR(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));126regs_.MarkGPRDirty(inst.dest, resultNormalized);127} else if (inst.src1 != inst.dest) {128regs_.Map(inst);129MOVE(regs_.R(inst.dest), regs_.R(inst.src1));130regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));131}132break;133134case IROp::Xor:135if (inst.src1 == inst.src2) {136regs_.SetGPRImm(inst.dest, 0);137} else {138regs_.Map(inst);139XOR(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));140}141break;142143case IROp::AndConst:144resultNormalized = regs_.IsNormalized32(inst.src1);145regs_.Map(inst);146// LoongArch64's ANDI use unsigned 12-bit immediate147if ((int32_t)inst.constant >= 0 && (int32_t)inst.constant < 4096) {148ANDI(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant);149} else {150LI(SCRATCH1, (int32_t)inst.constant);151AND(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1);152}153// If the sign bits aren't cleared, and it was normalized before - it still is.154if ((inst.constant & 0x80000000) != 0 && resultNormalized)155regs_.MarkGPRDirty(inst.dest, true);156// Otherwise, if we cleared the sign bits, it's naturally normalized.157else if ((inst.constant & 0x80000000) == 0)158regs_.MarkGPRDirty(inst.dest, true);159break;160161case IROp::OrConst:162resultNormalized = regs_.IsNormalized32(inst.src1);163regs_.Map(inst);164if ((int32_t)inst.constant >= 0 && (int32_t)inst.constant < 4096) {165ORI(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant);166} else {167LI(SCRATCH1, (int32_t)inst.constant);168OR(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1);169}170// Since our constant is normalized, oring its bits in won't hurt normalization.171regs_.MarkGPRDirty(inst.dest, resultNormalized);172break;173174case IROp::XorConst:175regs_.Map(inst);176if ((int32_t)inst.constant >= 0 && (int32_t)inst.constant < 4096) {177XORI(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant);178} else {179LI(SCRATCH1, (int32_t)inst.constant);180XOR(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1);181}182break;183184case IROp::Not:185regs_.Map(inst);186ORN(regs_.R(inst.dest), R_ZERO, regs_.R(inst.src1));187break;188189default:190INVALIDOP;191break;192}193}194195void LoongArch64JitBackend::CompIR_Assign(IRInst inst) {196CONDITIONAL_DISABLE;197198switch (inst.op) {199case IROp::Mov:200if (inst.dest != inst.src1) {201regs_.Map(inst);202MOVE(regs_.R(inst.dest), regs_.R(inst.src1));203regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));204}205break;206207case IROp::Ext8to32:208regs_.Map(inst);209EXT_W_B(regs_.R(inst.dest), regs_.R(inst.src1));210regs_.MarkGPRDirty(inst.dest, true);211break;212213case IROp::Ext16to32:214regs_.Map(inst);215EXT_W_H(regs_.R(inst.dest), regs_.R(inst.src1));216regs_.MarkGPRDirty(inst.dest, true);217break;218219default:220INVALIDOP;221break;222}223}224225void LoongArch64JitBackend::CompIR_Bits(IRInst inst) {226CONDITIONAL_DISABLE;227228switch (inst.op) {229case IROp::ReverseBits:230regs_.Map(inst);231BITREV_W(regs_.R(inst.dest), regs_.R(inst.src1));232regs_.MarkGPRDirty(inst.dest, true);233break;234235case IROp::BSwap16:236regs_.Map(inst);237REVB_2H(regs_.R(inst.dest), regs_.R(inst.src1));238regs_.MarkGPRDirty(inst.dest, true);239break;240241case IROp::BSwap32:242regs_.Map(inst);243REVB_2W(regs_.R(inst.dest), regs_.R(inst.src1));244regs_.MarkGPRDirty(inst.dest, true);245break;246247case IROp::Clz:248regs_.Map(inst);249CLZ_W(regs_.R(inst.dest), regs_.R(inst.src1));250regs_.MarkGPRDirty(inst.dest, true);251break;252253default:254INVALIDOP;255break;256}257}258259void LoongArch64JitBackend::CompIR_Shift(IRInst inst) {260CONDITIONAL_DISABLE;261262switch (inst.op) {263case IROp::Shl:264regs_.Map(inst);265SLL_W(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));266regs_.MarkGPRDirty(inst.dest, true);267break;268269case IROp::Shr:270regs_.Map(inst);271SRL_W(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));272regs_.MarkGPRDirty(inst.dest, true);273break;274275case IROp::Sar:276regs_.Map(inst);277SRA_W(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));278regs_.MarkGPRDirty(inst.dest, true);279break;280281case IROp::Ror:282regs_.Map(inst);283ROTR_W(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2));284regs_.MarkGPRDirty(inst.dest, true);285break;286287case IROp::ShlImm:288// Shouldn't happen, but let's be safe of any passes that modify the ops.289if (inst.src2 >= 32) {290regs_.SetGPRImm(inst.dest, 0);291} else if (inst.src2 == 0) {292if (inst.dest != inst.src1) {293regs_.Map(inst);294MOVE(regs_.R(inst.dest), regs_.R(inst.src1));295regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));296}297} else {298regs_.Map(inst);299SLLI_W(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2);300regs_.MarkGPRDirty(inst.dest, true);301}302break;303304case IROp::ShrImm:305// Shouldn't happen, but let's be safe of any passes that modify the ops.306if (inst.src2 >= 32) {307regs_.SetGPRImm(inst.dest, 0);308} else if (inst.src2 == 0) {309if (inst.dest != inst.src1) {310regs_.Map(inst);311MOVE(regs_.R(inst.dest), regs_.R(inst.src1));312regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));313}314} else {315regs_.Map(inst);316SRLI_W(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2);317regs_.MarkGPRDirty(inst.dest, true);318}319break;320321case IROp::SarImm:322// Shouldn't happen, but let's be safe of any passes that modify the ops.323if (inst.src2 >= 32) {324regs_.Map(inst);325SRAI_W(regs_.R(inst.dest), regs_.R(inst.src1), 31);326regs_.MarkGPRDirty(inst.dest, true);327} else if (inst.src2 == 0) {328if (inst.dest != inst.src1) {329regs_.Map(inst);330MOVE(regs_.R(inst.dest), regs_.R(inst.src1));331regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));332}333} else {334regs_.Map(inst);335SRAI_W(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2);336regs_.MarkGPRDirty(inst.dest, true);337}338break;339340case IROp::RorImm:341if (inst.src2 == 0) {342if (inst.dest != inst.src1) {343regs_.Map(inst);344MOVE(regs_.R(inst.dest), regs_.R(inst.src1));345regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));346}347} else {348regs_.Map(inst);349ROTRI_W(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2 & 31);350regs_.MarkGPRDirty(inst.dest, true);351}352break;353354default:355INVALIDOP;356break;357}358}359360void LoongArch64JitBackend::CompIR_Compare(IRInst inst) {361CONDITIONAL_DISABLE;362363LoongArch64Reg lhs = INVALID_REG;364LoongArch64Reg rhs = INVALID_REG;365switch (inst.op) {366case IROp::Slt:367regs_.Map(inst);368NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);369370SLT(regs_.R(inst.dest), lhs, rhs);371regs_.MarkGPRDirty(inst.dest, true);372break;373374case IROp::SltConst:375if (inst.constant == 0) {376// Basically, getting the sign bit. Let's shift instead.377regs_.Map(inst);378SRLI_W(regs_.R(inst.dest), regs_.R(inst.src1), 31);379regs_.MarkGPRDirty(inst.dest, true);380} else {381regs_.Map(inst);382NormalizeSrc1(inst, &lhs, SCRATCH1, false);383384if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) {385SLTI(regs_.R(inst.dest), lhs, (int32_t)inst.constant);386} else {387LI(SCRATCH2, (int32_t)inst.constant);388SLT(regs_.R(inst.dest), lhs, SCRATCH2);389}390regs_.MarkGPRDirty(inst.dest, true);391}392break;393394case IROp::SltU:395regs_.Map(inst);396// It's still fine to sign extend, the biggest just get even bigger.397NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);398399SLTU(regs_.R(inst.dest), lhs, rhs);400regs_.MarkGPRDirty(inst.dest, true);401break;402403case IROp::SltUConst:404if (inst.constant == 0) {405regs_.SetGPRImm(inst.dest, 0);406} else {407regs_.Map(inst);408NormalizeSrc1(inst, &lhs, SCRATCH1, false);409410// We sign extend because we're comparing against something normalized.411// It's also the most efficient to set.412if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) {413SLTUI(regs_.R(inst.dest), lhs, (int32_t)inst.constant);414} else {415LI(SCRATCH2, (int32_t)inst.constant);416SLTU(regs_.R(inst.dest), lhs, SCRATCH2);417}418regs_.MarkGPRDirty(inst.dest, true);419}420break;421422default:423INVALIDOP;424break;425}426}427428void LoongArch64JitBackend::CompIR_CondAssign(IRInst inst) {429CONDITIONAL_DISABLE;430431LoongArch64Reg lhs = INVALID_REG;432LoongArch64Reg rhs = INVALID_REG;433FixupBranch fixup;434switch (inst.op) {435case IROp::MovZ:436case IROp::MovNZ:437if (inst.dest == inst.src2)438return;439440// We could have a "zero" with wrong upper due to XOR, so we have to normalize.441regs_.Map(inst);442NormalizeSrc1(inst, &lhs, SCRATCH1, true);443444switch (inst.op) {445case IROp::MovZ:446fixup = BNEZ(lhs);447break;448case IROp::MovNZ:449fixup = BEQZ(lhs);450break;451default:452INVALIDOP;453break;454}455456MOVE(regs_.R(inst.dest), regs_.R(inst.src2));457SetJumpTarget(fixup);458break;459460case IROp::Max:461if (inst.src1 != inst.src2) {462CompIR_Generic(inst);463} else if (inst.dest != inst.src1) {464regs_.Map(inst);465MOVE(regs_.R(inst.dest), regs_.R(inst.src1));466regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));467}468break;469470case IROp::Min:471if (inst.src1 != inst.src2) {472CompIR_Generic(inst);473} else if (inst.dest != inst.src1) {474regs_.Map(inst);475MOVE(regs_.R(inst.dest), regs_.R(inst.src1));476regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1));477}478break;479480default:481INVALIDOP;482break;483}484}485486void LoongArch64JitBackend::CompIR_HiLo(IRInst inst) {487CONDITIONAL_DISABLE;488489switch (inst.op) {490case IROp::MtLo:491regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::DIRTY } });492// 32-63 bits of IRREG_LO + 0-31 bits of inst.src1493BSTRINS_D(regs_.R(IRREG_LO), regs_.R(inst.src1), 31, 0);494break;495496case IROp::MtHi:497regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::DIRTY } });498BSTRINS_D(regs_.R(IRREG_LO), regs_.R(inst.src1), 63, 32);499break;500501case IROp::MfLo:502regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::INIT } });503// It won't be normalized, but that's fine...504MOVE(regs_.R(inst.dest), regs_.R(IRREG_LO));505break;506507case IROp::MfHi:508regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::INIT } });509SRAI_D(regs_.R(inst.dest), regs_.R(IRREG_LO), 32);510regs_.MarkGPRDirty(inst.dest, true);511break;512513default:514INVALIDOP;515break;516}517}518519void LoongArch64JitBackend::CompIR_Mult(IRInst inst) {520CONDITIONAL_DISABLE;521522auto putArgsIntoScratches = [&](LoongArch64Reg *lhs, LoongArch64Reg *rhs) {523MOVE(SCRATCH1, regs_.R(inst.src1));524MOVE(SCRATCH2, regs_.R(inst.src2));525*lhs = SCRATCH1;526*rhs = SCRATCH2;527};528529LoongArch64Reg lhs = INVALID_REG;530LoongArch64Reg rhs = INVALID_REG;531switch (inst.op) {532case IROp::Mult:533// TODO: Maybe IR could simplify when HI is not needed or clobbered?534regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::NOINIT } });535NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);536MUL_D(regs_.R(IRREG_LO), lhs, rhs);537break;538539case IROp::MultU:540// This is an "anti-norm32" case. Let's just zero always.541// TODO: If we could know that LO was only needed, we could use MULW.542regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::NOINIT } });543putArgsIntoScratches(&lhs, &rhs);544MULW_D_WU(regs_.R(IRREG_LO), lhs, rhs);545break;546547case IROp::Madd:548regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::DIRTY } });549NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);550MUL_D(SCRATCH1, lhs, rhs);551ADD_D(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1);552break;553554case IROp::MaddU:555regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::DIRTY } });556putArgsIntoScratches(&lhs, &rhs);557MULW_D_WU(SCRATCH1, lhs, rhs);558ADD_D(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1);559break;560561case IROp::Msub:562regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::DIRTY } });563NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);564MUL_D(SCRATCH1, lhs, rhs);565SUB_D(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1);566break;567568case IROp::MsubU:569regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::DIRTY } });570putArgsIntoScratches(&lhs, &rhs);571MULW_D_WU(SCRATCH1, lhs, rhs);572SUB_D(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1);573break;574575default:576INVALIDOP;577break;578}579}580581void LoongArch64JitBackend::CompIR_Div(IRInst inst) {582CONDITIONAL_DISABLE;583584LoongArch64Reg numReg, denomReg;585switch (inst.op) {586case IROp::Div:587regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::NOINIT } });588// We have to do this because of the divide by zero and overflow checks below.589NormalizeSrc12(inst, &numReg, &denomReg, SCRATCH1, SCRATCH2, true);590DIV_W(regs_.R(IRREG_LO), numReg, denomReg);591MOD_W(R_RA, numReg, denomReg);592// Now to combine them. We'll do more with them below...593BSTRINS_D(regs_.R(IRREG_LO), R_RA, 63, 32);594595// Now some tweaks for divide by zero and overflow.596{597// Start with divide by zero, the quotient and remainder are arbitrary numbers.598FixupBranch skipNonZero = BNEZ(denomReg);599// Clear the arbitrary number600XOR(regs_.R(IRREG_LO), regs_.R(IRREG_LO), regs_.R(IRREG_LO));601// Replace remainder to numReg602BSTRINS_D(regs_.R(IRREG_LO), numReg, 63, 32);603FixupBranch keepNegOne = BGE(numReg, R_ZERO);604// Replace quotient with 1.605ADDI_D(regs_.R(IRREG_LO), regs_.R(IRREG_LO), 1);606SetJumpTarget(keepNegOne);607// Replace quotient with -1.608ADDI_D(regs_.R(IRREG_LO), regs_.R(IRREG_LO), -1);609SetJumpTarget(skipNonZero);610611// For overflow, LoongArch sets LO right, but remainder to zero.612// Cheating a bit by using R_RA as a temp...613LI(R_RA, (int32_t)0x80000000);614FixupBranch notMostNegative = BNE(numReg, R_RA);615LI(R_RA, -1);616FixupBranch notNegativeOne = BNE(denomReg, R_RA);617// Take our R_RA and put it in the high bits.618SLLI_D(R_RA, R_RA, 32);619OR(regs_.R(IRREG_LO), regs_.R(IRREG_LO), R_RA);620SetJumpTarget(notNegativeOne);621SetJumpTarget(notMostNegative);622}623break;624625case IROp::DivU:626regs_.MapWithExtra(inst, { { 'G', IRREG_LO, 2, MIPSMap::NOINIT } });627// We have to do this because of the divide by zero check below.628NormalizeSrc12(inst, &numReg, &denomReg, SCRATCH1, SCRATCH2, true);629DIV_WU(regs_.R(IRREG_LO), numReg, denomReg);630MOD_WU(R_RA, numReg, denomReg);631632// On divide by zero, special dealing with the 0xFFFF case.633{634FixupBranch skipNonZero = BNEZ(denomReg);635// Move -1 to quotient.636ADDI_D(regs_.R(IRREG_LO), R_ZERO, -1);637// Move numReg to remainder (stores in RA currently).638MOVE(R_RA, numReg);639// Luckily, we don't need SCRATCH2/denomReg anymore.640LI(SCRATCH2, 0xFFFF);641FixupBranch keepNegOne = BLTU(SCRATCH2, numReg);642MOVE(regs_.R(IRREG_LO), SCRATCH2);643SetJumpTarget(keepNegOne);644SetJumpTarget(skipNonZero);645}646647// Now combine the remainder in.648BSTRINS_D(regs_.R(IRREG_LO), R_RA, 63, 32);649break;650651default:652INVALIDOP;653break;654}655}656657} // namespace MIPSComp658659660