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/RiscVCompFPU.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/MIPS/RiscV/RiscVJit.h"18#include "Core/MIPS/RiscV/RiscVRegCache.h"1920// This file contains compilation for floating point related instructions.21//22// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.23// Currently known non working ones should have DISABLE. No flags because that's in IR already.2425// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }26#define CONDITIONAL_DISABLE {}27#define DISABLE { CompIR_Generic(inst); return; }28#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }2930namespace MIPSComp {3132using namespace RiscVGen;33using namespace RiscVJitConstants;3435void RiscVJitBackend::CompIR_FArith(IRInst inst) {36CONDITIONAL_DISABLE;3738switch (inst.op) {39case IROp::FAdd:40regs_.Map(inst);41FADD(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));42break;4344case IROp::FSub:45regs_.Map(inst);46FSUB(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));47break;4849case IROp::FMul:50regs_.Map(inst);51// We'll assume everyone will make it such that 0 * infinity = NAN properly.52// See blame on this comment if that proves untrue.53FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));54break;5556case IROp::FDiv:57regs_.Map(inst);58FDIV(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));59break;6061case IROp::FSqrt:62regs_.Map(inst);63FSQRT(32, regs_.F(inst.dest), regs_.F(inst.src1));64break;6566case IROp::FNeg:67regs_.Map(inst);68FNEG(32, regs_.F(inst.dest), regs_.F(inst.src1));69break;7071default:72INVALIDOP;73break;74}75}7677void RiscVJitBackend::CompIR_FCondAssign(IRInst inst) {78CONDITIONAL_DISABLE;79if (inst.op != IROp::FMin && inst.op != IROp::FMax)80INVALIDOP;81bool maxCondition = inst.op == IROp::FMax;8283// FMin and FMax are used by VFPU and handle NAN/INF as just a larger exponent.84regs_.Map(inst);85FCLASS(32, SCRATCH1, regs_.F(inst.src1));86FCLASS(32, SCRATCH2, regs_.F(inst.src2));8788// If either side is a NAN, it needs to participate in the comparison.89OR(SCRATCH1, SCRATCH1, SCRATCH2);90// NAN is either 0x100 or 0x200.91ANDI(SCRATCH1, SCRATCH1, 0x300);92FixupBranch useNormalCond = BEQ(SCRATCH1, R_ZERO);9394// Time to use bits... classify won't help because it ignores -NAN.95FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1));96FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src2));9798// If both are negative, we flip the comparison (not two's compliment.)99// We cheat and use RA...100AND(R_RA, SCRATCH1, SCRATCH2);101SRLIW(R_RA, R_RA, 31);102103if (cpu_info.RiscV_Zbb) {104FixupBranch swapCompare = BNE(R_RA, R_ZERO);105if (maxCondition)106MAX(SCRATCH1, SCRATCH1, SCRATCH2);107else108MIN(SCRATCH1, SCRATCH1, SCRATCH2);109FixupBranch skipSwapCompare = J();110SetJumpTarget(swapCompare);111if (maxCondition)112MIN(SCRATCH1, SCRATCH1, SCRATCH2);113else114MAX(SCRATCH1, SCRATCH1, SCRATCH2);115SetJumpTarget(skipSwapCompare);116} else {117RiscVReg isSrc1LowerReg = regs_.GetAndLockTempGPR();118SLT(isSrc1LowerReg, SCRATCH1, SCRATCH2);119// Flip the flag (to reverse the min/max) based on if both were negative.120XOR(isSrc1LowerReg, isSrc1LowerReg, R_RA);121FixupBranch useSrc1;122if (maxCondition)123useSrc1 = BEQ(isSrc1LowerReg, R_ZERO);124else125useSrc1 = BNE(isSrc1LowerReg, R_ZERO);126MV(SCRATCH1, SCRATCH2);127SetJumpTarget(useSrc1);128}129130FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1);131FixupBranch finish = J();132133SetJumpTarget(useNormalCond);134if (maxCondition)135FMAX(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));136else137FMIN(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));138SetJumpTarget(finish);139}140141void RiscVJitBackend::CompIR_FAssign(IRInst inst) {142CONDITIONAL_DISABLE;143144switch (inst.op) {145case IROp::FMov:146if (inst.dest != inst.src1) {147regs_.Map(inst);148FMV(32, regs_.F(inst.dest), regs_.F(inst.src1));149}150break;151152case IROp::FAbs:153regs_.Map(inst);154FABS(32, regs_.F(inst.dest), regs_.F(inst.src1));155break;156157case IROp::FSign:158{159regs_.Map(inst);160// Check if it's negative zero, either 0x10/0x08 is zero.161FCLASS(32, SCRATCH1, regs_.F(inst.src1));162ANDI(SCRATCH1, SCRATCH1, 0x18);163SEQZ(SCRATCH1, SCRATCH1);164// Okay, it's zero if zero, 1 otherwise. Convert 1 to a constant 1.0.165// Probably non-zero is the common case, so we make that the straight line.166FixupBranch skipOne = BEQ(SCRATCH1, R_ZERO);167LI(SCRATCH1, 1.0f);168169// Now we just need the sign from it.170FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src1));171// Use a wall to isolate the sign, and combine.172SRAIW(SCRATCH2, SCRATCH2, 31);173SLLIW(SCRATCH2, SCRATCH2, 31);174OR(SCRATCH1, SCRATCH1, SCRATCH2);175176SetJumpTarget(skipOne);177FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1);178break;179}180181default:182INVALIDOP;183break;184}185}186187void RiscVJitBackend::CompIR_FRound(IRInst inst) {188CONDITIONAL_DISABLE;189190// TODO: If this is followed by a GPR transfer, might want to combine.191regs_.Map(inst);192193switch (inst.op) {194case IROp::FRound:195FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::NEAREST_EVEN);196break;197198case IROp::FTrunc:199FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::TOZERO);200break;201202case IROp::FCeil:203FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::UP);204break;205206case IROp::FFloor:207FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::DOWN);208break;209210default:211INVALIDOP;212break;213}214215FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1);216}217218void RiscVJitBackend::CompIR_FCvt(IRInst inst) {219CONDITIONAL_DISABLE;220221RiscVReg tempReg = INVALID_REG;222switch (inst.op) {223case IROp::FCvtWS:224CompIR_Generic(inst);225break;226227case IROp::FCvtSW:228// TODO: This is probably proceeded by a GPR transfer, might be ideal to combine.229regs_.Map(inst);230FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1));231FCVT(FConv::S, FConv::W, regs_.F(inst.dest), SCRATCH1);232break;233234case IROp::FCvtScaledWS:235{236Round rm = Round::NEAREST_EVEN;237switch (inst.src2 >> 6) {238case 0: rm = Round::NEAREST_EVEN; break;239case 1: rm = Round::TOZERO; break;240case 2: rm = Round::UP; break;241case 3: rm = Round::DOWN; break;242default:243_assert_msg_(false, "Invalid rounding mode for FCvtScaledWS");244}245246tempReg = regs_.MapWithFPRTemp(inst);247// Prepare the multiplier.248QuickFLI(32, tempReg, (float)(1UL << (inst.src2 & 0x1F)), SCRATCH1);249250FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1), tempReg, rm);251// NAN and clamping should all be correct.252FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.dest), rm);253// TODO: Could combine with a transfer, often is one...254FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1);255break;256}257258case IROp::FCvtScaledSW:259// TODO: This is probably proceeded by a GPR transfer, might be ideal to combine.260tempReg = regs_.MapWithFPRTemp(inst);261FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1));262FCVT(FConv::S, FConv::W, regs_.F(inst.dest), SCRATCH1);263264// Pre-divide so we can avoid any actual divide.265QuickFLI(32, tempReg, 1.0f / (1UL << (inst.src2 & 0x1F)), SCRATCH1);266FMUL(32, regs_.F(inst.dest), regs_.F(inst.dest), tempReg);267break;268269default:270INVALIDOP;271break;272}273}274275void RiscVJitBackend::CompIR_FSat(IRInst inst) {276CONDITIONAL_DISABLE;277278RiscVReg tempReg = INVALID_REG;279FixupBranch skipLower;280FixupBranch finishLower;281FixupBranch skipHigher;282switch (inst.op) {283case IROp::FSat0_1:284tempReg = regs_.MapWithFPRTemp(inst);285if (inst.dest != inst.src1)286FMV(32, regs_.F(inst.dest), regs_.F(inst.src1));287288// First, set SCRATCH1 = clamp to zero, SCRATCH2 = clamp to one.289FCVT(FConv::S, FConv::W, tempReg, R_ZERO);290// FLE here is intentional to convert -0.0 to +0.0.291FLE(32, SCRATCH1, regs_.F(inst.src1), tempReg);292QuickFLI(32, tempReg, 1.0f, SCRATCH2);293FLT(32, SCRATCH2, tempReg, regs_.F(inst.src1));294295skipLower = BEQ(SCRATCH1, R_ZERO);296FCVT(FConv::S, FConv::W, regs_.F(inst.dest), R_ZERO);297finishLower = J();298299SetJumpTarget(skipLower);300skipHigher = BEQ(SCRATCH2, R_ZERO);301// Still has 1.0 in it.302FMV(32, regs_.F(inst.dest), tempReg);303304SetJumpTarget(finishLower);305SetJumpTarget(skipHigher);306break;307308case IROp::FSatMinus1_1:309tempReg = regs_.MapWithFPRTemp(inst);310if (inst.dest != inst.src1)311FMV(32, regs_.F(inst.dest), regs_.F(inst.src1));312313// First, set SCRATCH1 = clamp to negative, SCRATCH2 = clamp to positive.314QuickFLI(32, tempReg, -1.0f, SCRATCH2);315FLT(32, SCRATCH1, regs_.F(inst.src1), tempReg);316FNEG(32, tempReg, tempReg);317FLT(32, SCRATCH2, tempReg, regs_.F(inst.src1));318319// But we can actually do one branch, using sign-injection to keep the original sign.320OR(SCRATCH1, SCRATCH1, SCRATCH2);321322skipLower = BEQ(SCRATCH1, R_ZERO);323FSGNJ(32, regs_.F(inst.dest), tempReg, regs_.F(inst.dest));324SetJumpTarget(skipLower);325break;326327default:328INVALIDOP;329break;330}331}332333void RiscVJitBackend::CompIR_FCompare(IRInst inst) {334CONDITIONAL_DISABLE;335336constexpr IRReg IRREG_VFPU_CC = IRREG_VFPU_CTRL_BASE + VFPU_CTRL_CC;337338switch (inst.op) {339case IROp::FCmp:340switch (inst.dest) {341case IRFpCompareMode::False:342regs_.SetGPRImm(IRREG_FPCOND, 0);343break;344345case IRFpCompareMode::EitherUnordered:346regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });347FCLASS(32, SCRATCH1, regs_.F(inst.src1));348FCLASS(32, SCRATCH2, regs_.F(inst.src2));349OR(SCRATCH1, SCRATCH1, SCRATCH2);350// NAN is 0x100 or 0x200.351ANDI(SCRATCH1, SCRATCH1, 0x300);352SNEZ(regs_.R(IRREG_FPCOND), SCRATCH1);353regs_.MarkGPRDirty(IRREG_FPCOND, true);354break;355356case IRFpCompareMode::EqualOrdered:357regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });358FEQ(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2));359regs_.MarkGPRDirty(IRREG_FPCOND, true);360break;361362case IRFpCompareMode::EqualUnordered:363regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });364FEQ(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2));365366// Now let's just OR in the unordered check.367FCLASS(32, SCRATCH1, regs_.F(inst.src1));368FCLASS(32, SCRATCH2, regs_.F(inst.src2));369OR(SCRATCH1, SCRATCH1, SCRATCH2);370// NAN is 0x100 or 0x200.371ANDI(SCRATCH1, SCRATCH1, 0x300);372SNEZ(SCRATCH1, SCRATCH1);373OR(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND), SCRATCH1);374regs_.MarkGPRDirty(IRREG_FPCOND, true);375break;376377case IRFpCompareMode::LessEqualOrdered:378regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });379FLE(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2));380regs_.MarkGPRDirty(IRREG_FPCOND, true);381break;382383case IRFpCompareMode::LessEqualUnordered:384regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });385FLT(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src2), regs_.F(inst.src1));386SEQZ(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND));387regs_.MarkGPRDirty(IRREG_FPCOND, true);388break;389390case IRFpCompareMode::LessOrdered:391regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });392FLT(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2));393regs_.MarkGPRDirty(IRREG_FPCOND, true);394break;395396case IRFpCompareMode::LessUnordered:397regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });398FLE(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src2), regs_.F(inst.src1));399SEQZ(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND));400regs_.MarkGPRDirty(IRREG_FPCOND, true);401break;402403default:404_assert_msg_(false, "Unexpected IRFpCompareMode %d", inst.dest);405}406break;407408case IROp::FCmovVfpuCC:409regs_.MapWithExtra(inst, { { 'G', IRREG_VFPU_CC, 1, MIPSMap::INIT } });410if ((inst.src2 & 0xF) == 0) {411ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), 1);412} else if (cpu_info.RiscV_Zbs) {413BEXTI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.src2 & 0xF);414} else {415SRLI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.src2 & 0xF);416ANDI(SCRATCH1, SCRATCH1, 1);417}418if ((inst.src2 >> 7) & 1) {419FixupBranch skip = BEQ(SCRATCH1, R_ZERO);420FMV(32, regs_.F(inst.dest), regs_.F(inst.src1));421SetJumpTarget(skip);422} else {423FixupBranch skip = BNE(SCRATCH1, R_ZERO);424FMV(32, regs_.F(inst.dest), regs_.F(inst.src1));425SetJumpTarget(skip);426}427break;428429case IROp::FCmpVfpuBit:430regs_.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY);431432switch (VCondition(inst.dest & 0xF)) {433case VC_EQ:434regs_.Map(inst);435FEQ(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2));436break;437case VC_NE:438regs_.Map(inst);439FEQ(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2));440SEQZ(SCRATCH1, SCRATCH1);441break;442case VC_LT:443regs_.Map(inst);444FLT(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2));445break;446case VC_LE:447regs_.Map(inst);448FLE(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2));449break;450case VC_GT:451regs_.Map(inst);452FLT(32, SCRATCH1, regs_.F(inst.src2), regs_.F(inst.src1));453break;454case VC_GE:455regs_.Map(inst);456FLE(32, SCRATCH1, regs_.F(inst.src2), regs_.F(inst.src1));457break;458case VC_EZ:459case VC_NZ:460regs_.MapFPR(inst.src1);461// Zero is either 0x10 or 0x08.462FCLASS(32, SCRATCH1, regs_.F(inst.src1));463ANDI(SCRATCH1, SCRATCH1, 0x18);464if ((inst.dest & 4) == 0)465SNEZ(SCRATCH1, SCRATCH1);466else467SEQZ(SCRATCH1, SCRATCH1);468break;469case VC_EN:470case VC_NN:471regs_.MapFPR(inst.src1);472// NAN is either 0x100 or 0x200.473FCLASS(32, SCRATCH1, regs_.F(inst.src1));474ANDI(SCRATCH1, SCRATCH1, 0x300);475if ((inst.dest & 4) == 0)476SNEZ(SCRATCH1, SCRATCH1);477else478SEQZ(SCRATCH1, SCRATCH1);479break;480case VC_EI:481case VC_NI:482regs_.MapFPR(inst.src1);483// Infinity is either 0x80 or 0x01.484FCLASS(32, SCRATCH1, regs_.F(inst.src1));485ANDI(SCRATCH1, SCRATCH1, 0x81);486if ((inst.dest & 4) == 0)487SNEZ(SCRATCH1, SCRATCH1);488else489SEQZ(SCRATCH1, SCRATCH1);490break;491case VC_ES:492case VC_NS:493regs_.MapFPR(inst.src1);494// Infinity is either 0x80 or 0x01, NAN is either 0x100 or 0x200.495FCLASS(32, SCRATCH1, regs_.F(inst.src1));496ANDI(SCRATCH1, SCRATCH1, 0x381);497if ((inst.dest & 4) == 0)498SNEZ(SCRATCH1, SCRATCH1);499else500SEQZ(SCRATCH1, SCRATCH1);501break;502case VC_TR:503LI(SCRATCH1, 1);504break;505case VC_FL:506LI(SCRATCH1, 0);507break;508}509510ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~(1 << (inst.dest >> 4)));511if ((inst.dest >> 4) != 0)512SLLI(SCRATCH1, SCRATCH1, inst.dest >> 4);513OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1);514break;515516case IROp::FCmpVfpuAggregate:517regs_.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY);518if (inst.dest == 1) {519ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.dest);520// Negate so 1 becomes all bits set and zero stays zero, then mask to 0x30.521NEG(SCRATCH1, SCRATCH1);522ANDI(SCRATCH1, SCRATCH1, 0x30);523524// Reject the old any/all bits and replace them with our own.525ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~0x30);526OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1);527} else {528ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.dest);529FixupBranch skipZero = BEQ(SCRATCH1, R_ZERO);530531// To compare to inst.dest for "all", let's simply subtract it and compare to zero.532ADDI(SCRATCH1, SCRATCH1, -inst.dest);533SEQZ(SCRATCH1, SCRATCH1);534// Now we combine with the "any" bit.535SLLI(SCRATCH1, SCRATCH1, 5);536ORI(SCRATCH1, SCRATCH1, 0x10);537538SetJumpTarget(skipZero);539540// Reject the old any/all bits and replace them with our own.541ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~0x30);542OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1);543}544break;545546default:547INVALIDOP;548break;549}550}551552void RiscVJitBackend::CompIR_RoundingMode(IRInst inst) {553CONDITIONAL_DISABLE;554555switch (inst.op) {556case IROp::RestoreRoundingMode:557RestoreRoundingMode();558break;559560case IROp::ApplyRoundingMode:561ApplyRoundingMode();562break;563564case IROp::UpdateRoundingMode:565// We don't need to do anything, instructions allow a "dynamic" rounding mode.566break;567568default:569INVALIDOP;570break;571}572}573574void RiscVJitBackend::CompIR_FSpecial(IRInst inst) {575CONDITIONAL_DISABLE;576577#ifdef __riscv_float_abi_soft578#error Currently hard float is required.579#endif580581auto callFuncF_F = [&](float (*func)(float)) {582regs_.FlushBeforeCall();583WriteDebugProfilerStatus(IRProfilerStatus::MATH_HELPER);584585// It might be in a non-volatile register.586// TODO: May have to handle a transfer if SIMD here.587if (regs_.IsFPRMapped(inst.src1)) {588FMV(32, F10, regs_.F(inst.src1));589} else {590int offset = offsetof(MIPSState, f) + inst.src1 * 4;591FL(32, F10, CTXREG, offset);592}593QuickCallFunction(func, SCRATCH1);594595regs_.MapFPR(inst.dest, MIPSMap::NOINIT);596// If it's already F10, we're done - MapReg doesn't actually overwrite the reg in that case.597if (regs_.F(inst.dest) != F10) {598FMV(32, regs_.F(inst.dest), F10);599}600601WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);602};603604RiscVReg tempReg = INVALID_REG;605switch (inst.op) {606case IROp::FSin:607callFuncF_F(&vfpu_sin);608break;609610case IROp::FCos:611callFuncF_F(&vfpu_cos);612break;613614case IROp::FRSqrt:615tempReg = regs_.MapWithFPRTemp(inst);616FSQRT(32, regs_.F(inst.dest), regs_.F(inst.src1));617618// Ugh, we can't really avoid a temp here. Probably not worth a permanent one.619QuickFLI(32, tempReg, 1.0f, SCRATCH1);620FDIV(32, regs_.F(inst.dest), tempReg, regs_.F(inst.dest));621break;622623case IROp::FRecip:624if (inst.dest != inst.src1) {625// This is the easy case.626regs_.Map(inst);627LI(SCRATCH1, 1.0f);628FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1);629FDIV(32, regs_.F(inst.dest), regs_.F(inst.dest), regs_.F(inst.src1));630} else {631tempReg = regs_.MapWithFPRTemp(inst);632QuickFLI(32, tempReg, 1.0f, SCRATCH1);633FDIV(32, regs_.F(inst.dest), tempReg, regs_.F(inst.src1));634}635break;636637case IROp::FAsin:638callFuncF_F(&vfpu_asin);639break;640641default:642INVALIDOP;643break;644}645}646647} // namespace MIPSComp648649650