Path: blob/master/Core/MIPS/LoongArch64/LoongArch64CompFPU.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 floating point related 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::CompIR_FArith(IRInst inst) {37CONDITIONAL_DISABLE;3839switch (inst.op) {40case IROp::FAdd:41regs_.Map(inst);42FADD_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));43break;4445case IROp::FSub:46regs_.Map(inst);47FSUB_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));48break;4950case IROp::FMul:51regs_.Map(inst);52// We'll assume everyone will make it such that 0 * infinity = NAN properly.53// See blame on this comment if that proves untrue.54FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));55break;5657case IROp::FDiv:58regs_.Map(inst);59FDIV_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));60break;6162case IROp::FSqrt:63regs_.Map(inst);64FSQRT_S(regs_.F(inst.dest), regs_.F(inst.src1));65break;6667case IROp::FNeg:68regs_.Map(inst);69FNEG_S(regs_.F(inst.dest), regs_.F(inst.src1));70break;7172default:73INVALIDOP;74break;75}76}7778void LoongArch64JitBackend::CompIR_FCondAssign(IRInst inst) {79CONDITIONAL_DISABLE;8081regs_.Map(inst);82FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CUN);83MOVCF2GR(SCRATCH1, FCC0);84FixupBranch unordered = BNEZ(SCRATCH1);8586switch (inst.op) {87case IROp::FMin:88FMIN_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));89break;9091case IROp::FMax:92FMAX_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));93break;9495default:96INVALIDOP;97break;98}99100FixupBranch ordererDone = B();101SetJumpTarget(unordered);102103MOVFR2GR_S(SCRATCH1, regs_.F(inst.src1));104MOVFR2GR_S(SCRATCH2, regs_.F(inst.src2));105106// If both are negative, we flip the comparison (not two's compliment.)107// We cheat and use RA...108AND(R_RA, SCRATCH1, SCRATCH2);109SRLI_W(R_RA, R_RA, 31);110111LoongArch64Reg isSrc1LowerReg = regs_.GetAndLockTempGPR();112SLT(isSrc1LowerReg, SCRATCH1, SCRATCH2);113// Flip the flag (to reverse the min/max) based on if both were negative.114XOR(isSrc1LowerReg, isSrc1LowerReg, R_RA);115FixupBranch useSrc1;116switch (inst.op) {117case IROp::FMin:118useSrc1 = BNEZ(isSrc1LowerReg);119break;120121case IROp::FMax:122useSrc1 = BEQZ(isSrc1LowerReg);123break;124125default:126INVALIDOP;127break;128}129MOVE(SCRATCH1, SCRATCH2);130SetJumpTarget(useSrc1);131132MOVGR2FR_W(regs_.F(inst.dest), SCRATCH1);133134SetJumpTarget(ordererDone);135}136137void LoongArch64JitBackend::CompIR_FAssign(IRInst inst) {138CONDITIONAL_DISABLE;139140switch (inst.op) {141case IROp::FMov:142if (inst.dest != inst.src1) {143regs_.Map(inst);144FMOV_S(regs_.F(inst.dest), regs_.F(inst.src1));145}146break;147148case IROp::FAbs:149regs_.Map(inst);150FABS_S(regs_.F(inst.dest), regs_.F(inst.src1));151break;152153case IROp::FSign:154{155regs_.Map(inst);156// Check if it's negative zero, either 0x20/0x200 is zero.157FCLASS_S(SCRATCHF1, regs_.F(inst.src1));158MOVFR2GR_S(SCRATCH1, SCRATCHF1);159ANDI(SCRATCH1, SCRATCH1, 0x220);160SLTUI(SCRATCH1, SCRATCH1, 1);161// Okay, it's zero if zero, 1 otherwise. Convert 1 to a constant 1.0.162// Probably non-zero is the common case, so we make that the straight line.163FixupBranch skipOne = BEQZ(SCRATCH1);164LI(SCRATCH1, 1.0f);165166// Now we just need the sign from it.167MOVFR2GR_S(SCRATCH2, regs_.F(inst.src1));168// Use a wall to isolate the sign, and combine.169SRAI_W(SCRATCH2, SCRATCH2, 31);170SLLI_W(SCRATCH2, SCRATCH2, 31);171OR(SCRATCH1, SCRATCH1, SCRATCH2);172173SetJumpTarget(skipOne);174MOVGR2FR_W(regs_.F(inst.dest), SCRATCH1);175break;176}177178default:179INVALIDOP;180break;181}182}183184void LoongArch64JitBackend::CompIR_FRound(IRInst inst) {185CONDITIONAL_DISABLE;186187regs_.Map(inst);188// FTINT* instruction will convert NAN to zero, tested on 3A6000.189QuickFLI(32, SCRATCHF1, (uint32_t)0x7fffffffl, SCRATCH1);190FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src1), LoongArch64Fcond::CUN);191192switch (inst.op) {193case IROp::FRound:194FTINTRNE_W_S(regs_.F(inst.dest), regs_.F(inst.src1));195break;196197case IROp::FTrunc:198FTINTRZ_W_S(regs_.F(inst.dest), regs_.F(inst.src1));199break;200201case IROp::FCeil:202FTINTRP_W_S(regs_.F(inst.dest), regs_.F(inst.src1));203break;204205case IROp::FFloor:206FTINTRM_W_S(regs_.F(inst.dest), regs_.F(inst.src1));207break;208209default:210INVALIDOP;211break;212}213214// Switch to INT_MAX if it was NAN.215FSEL(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF1, FCC0);216}217218void LoongArch64JitBackend::CompIR_FCvt(IRInst inst) {219CONDITIONAL_DISABLE;220221switch (inst.op) {222case IROp::FCvtWS:223CompIR_Generic(inst);224break;225226case IROp::FCvtSW:227regs_.Map(inst);228FFINT_S_W(regs_.F(inst.dest), regs_.F(inst.src1));229break;230231case IROp::FCvtScaledWS:232regs_.Map(inst);233// Prepare for the NAN result234QuickFLI(32, SCRATCHF1, (uint32_t)(0x7FFFFFFF), SCRATCH1);235// Prepare the multiplier.236QuickFLI(32, SCRATCHF1, (float)(1UL << (inst.src2 & 0x1F)), SCRATCH1);237238switch (inst.src2 >> 6) {239case 0: // RNE240FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src1), LoongArch64Fcond::CUN);241FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1), SCRATCHF1);242FTINTRNE_W_S(regs_.F(inst.dest), regs_.F(inst.dest));243FSEL(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF2, FCC0);244break;245case 1: // RZ246FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src1), LoongArch64Fcond::CUN);247FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1), SCRATCHF1);248FTINTRZ_W_S(regs_.F(inst.dest), regs_.F(inst.dest));249FSEL(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF2, FCC0);250break;251case 2: // RP252FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src1), LoongArch64Fcond::CUN);253FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1), SCRATCHF1);254FTINTRP_W_S(regs_.F(inst.dest), regs_.F(inst.dest));255FSEL(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF2, FCC0);256break;257case 3: // RM258FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src1), LoongArch64Fcond::CUN);259FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1), SCRATCHF1);260FTINTRM_W_S(regs_.F(inst.dest), regs_.F(inst.dest));261FSEL(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF2, FCC0);262break;263default:264_assert_msg_(false, "Invalid rounding mode for FCvtScaledWS");265}266267break;268269case IROp::FCvtScaledSW:270regs_.Map(inst);271FFINT_S_W(regs_.F(inst.dest), regs_.F(inst.src1));272273// Pre-divide so we can avoid any actual divide.274QuickFLI(32, SCRATCHF1, 1.0f / (1UL << (inst.src2 & 0x1F)), SCRATCH1);275FMUL_S(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF1);276break;277278default:279INVALIDOP;280break;281}282}283284void LoongArch64JitBackend::CompIR_FSat(IRInst inst) {285CONDITIONAL_DISABLE;286287switch (inst.op) {288case IROp::FSat0_1:289regs_.Map(inst);290QuickFLI(32, SCRATCHF1, (float)1.0f, SCRATCH1);291// Check whether FMAX takes the larger of the two zeros, which is what we want.292QuickFLI(32, SCRATCHF2, (float)0.0f, SCRATCH1);293294FMIN_S(regs_.F(inst.dest), regs_.F(inst.src1), SCRATCHF1);295FMAX_S(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF2);296break;297298case IROp::FSatMinus1_1:299regs_.Map(inst);300QuickFLI(32, SCRATCHF1, (float)1.0f, SCRATCH1);301FNEG_S(SCRATCHF2, SCRATCHF1);302303FMIN_S(regs_.F(inst.dest), regs_.F(inst.src1), SCRATCHF1);304FMAX_S(regs_.F(inst.dest), regs_.F(inst.dest), SCRATCHF2);305break;306307default:308INVALIDOP;309break;310}311}312313void LoongArch64JitBackend::CompIR_FCompare(IRInst inst) {314CONDITIONAL_DISABLE;315316constexpr IRReg IRREG_VFPU_CC = IRREG_VFPU_CTRL_BASE + VFPU_CTRL_CC;317318switch (inst.op) {319case IROp::FCmp:320switch (inst.dest) {321case IRFpCompareMode::False:322regs_.SetGPRImm(IRREG_FPCOND, 0);323break;324325case IRFpCompareMode::EitherUnordered:326regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });327FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CUN);328MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);329regs_.MarkGPRDirty(IRREG_FPCOND, true);330break;331332case IRFpCompareMode::EqualOrdered:333regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });334FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CEQ);335MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);336regs_.MarkGPRDirty(IRREG_FPCOND, true);337break;338339case IRFpCompareMode::EqualUnordered:340regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });341FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CUEQ);342MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);343regs_.MarkGPRDirty(IRREG_FPCOND, true);344break;345346case IRFpCompareMode::LessEqualOrdered:347regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });348FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CLE);349MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);350regs_.MarkGPRDirty(IRREG_FPCOND, true);351break;352353case IRFpCompareMode::LessEqualUnordered:354regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });355FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CULE);356MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);357regs_.MarkGPRDirty(IRREG_FPCOND, true);358break;359360case IRFpCompareMode::LessOrdered:361regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });362FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CLT);363MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);364regs_.MarkGPRDirty(IRREG_FPCOND, true);365break;366367case IRFpCompareMode::LessUnordered:368regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });369FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CULT);370MOVCF2GR(regs_.R(IRREG_FPCOND), FCC0);371regs_.MarkGPRDirty(IRREG_FPCOND, true);372break;373374default:375_assert_msg_(false, "Unexpected IRFpCompareMode %d", inst.dest);376}377break;378379case IROp::FCmovVfpuCC:380regs_.MapWithExtra(inst, { { 'G', IRREG_VFPU_CC, 1, MIPSMap::INIT } });381if ((inst.src2 & 0xF) == 0) {382ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), 1);383} else {384BSTRPICK_D(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.src2 & 0xF, inst.src2 & 0xF);385}386if ((inst.src2 >> 7) & 1) {387FixupBranch skip = BEQZ(SCRATCH1);388FMOV_S(regs_.F(inst.dest), regs_.F(inst.src1));389SetJumpTarget(skip);390} else {391FixupBranch skip = BNEZ(SCRATCH1);392FMOV_S(regs_.F(inst.dest), regs_.F(inst.src1));393SetJumpTarget(skip);394}395break;396397case IROp::FCmpVfpuBit:398regs_.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY);399400switch (VCondition(inst.dest & 0xF)) {401case VC_EQ:402regs_.Map(inst);403FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CEQ);404MOVCF2GR(SCRATCH1, FCC0);405break;406case VC_NE:407regs_.Map(inst);408FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CNE);409MOVCF2GR(SCRATCH1, FCC0);410break;411case VC_LT:412regs_.Map(inst);413FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CLT);414MOVCF2GR(SCRATCH1, FCC0);415break;416case VC_LE:417regs_.Map(inst);418FCMP_COND_S(FCC0, regs_.F(inst.src1), regs_.F(inst.src2), LoongArch64Fcond::CLE);419MOVCF2GR(SCRATCH1, FCC0);420break;421case VC_GT:422regs_.Map(inst);423FCMP_COND_S(FCC0, regs_.F(inst.src2), regs_.F(inst.src1), LoongArch64Fcond::CLT);424MOVCF2GR(SCRATCH1, FCC0);425break;426case VC_GE:427regs_.Map(inst);428FCMP_COND_S(FCC0, regs_.F(inst.src2), regs_.F(inst.src1), LoongArch64Fcond::CLE);429MOVCF2GR(SCRATCH1, FCC0);430break;431case VC_EZ:432case VC_NZ:433regs_.MapFPR(inst.src1);434// Zero is either 0x20 or 0x200.435FCLASS_S(SCRATCHF1, regs_.F(inst.src1));436MOVFR2GR_S(SCRATCH1, SCRATCHF1);437ANDI(SCRATCH1, SCRATCH1, 0x220);438if ((inst.dest & 4) == 0)439SLTU(SCRATCH1, R_ZERO, SCRATCH1);440else441SLTUI(SCRATCH1, SCRATCH1, 1);442break;443case VC_EN:444case VC_NN:445regs_.MapFPR(inst.src1);446// NAN is either 0x1 or 0x2.447FCLASS_S(SCRATCHF1, regs_.F(inst.src1));448MOVFR2GR_S(SCRATCH1, SCRATCHF1);449ANDI(SCRATCH1, SCRATCH1, 0x3);450if ((inst.dest & 4) == 0)451SLTU(SCRATCH1, R_ZERO, SCRATCH1);452else453SLTUI(SCRATCH1, SCRATCH1, 1);454break;455case VC_EI:456case VC_NI:457regs_.MapFPR(inst.src1);458// Infinity is either 0x40 or 0x04.459FCLASS_S(SCRATCHF1, regs_.F(inst.src1));460MOVFR2GR_S(SCRATCH1, SCRATCHF1);461ANDI(SCRATCH1, SCRATCH1, 0x44);462if ((inst.dest & 4) == 0)463SLTU(SCRATCH1, R_ZERO, SCRATCH1);464else465SLTUI(SCRATCH1, SCRATCH1, 1);466break;467case VC_ES:468case VC_NS:469regs_.MapFPR(inst.src1);470// Infinity is either 0x40 or 0x04, NAN is either 0x1 or 0x2.471FCLASS_S(SCRATCHF1, regs_.F(inst.src1));472MOVFR2GR_S(SCRATCH1, SCRATCHF1);473ANDI(SCRATCH1, SCRATCH1, 0x47);474if ((inst.dest & 4) == 0)475SLTU(SCRATCH1, R_ZERO, SCRATCH1);476else477SLTUI(SCRATCH1, SCRATCH1, 1);478break;479case VC_TR:480LI(SCRATCH1, 1);481break;482case VC_FL:483LI(SCRATCH1, 0);484break;485}486487ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~(1 << (inst.dest >> 4)));488if ((inst.dest >> 4) != 0)489SLLI_D(SCRATCH1, SCRATCH1, inst.dest >> 4);490OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1);491break;492493case IROp::FCmpVfpuAggregate:494regs_.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY);495if (inst.dest == 1) {496ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.dest);497// Negate so 1 becomes all bits set and zero stays zero, then mask to 0x30.498SUB_D(SCRATCH1, R_ZERO, SCRATCH1);499ANDI(SCRATCH1, SCRATCH1, 0x30);500501// Reject the old any/all bits and replace them with our own.502ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~0x30);503OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1);504} else {505ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.dest);506FixupBranch skipZero = BEQZ(SCRATCH1);507508// To compare to inst.dest for "all", let's simply subtract it and compare to zero.509ADDI_D(SCRATCH1, SCRATCH1, -inst.dest);510SLTUI(SCRATCH1, SCRATCH1, 1);511// Now we combine with the "any" bit.512SLLI_D(SCRATCH1, SCRATCH1, 5);513ORI(SCRATCH1, SCRATCH1, 0x10);514515SetJumpTarget(skipZero);516517// Reject the old any/all bits and replace them with our own.518ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~0x30);519OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1);520}521break;522523default:524INVALIDOP;525break;526}527}528529void LoongArch64JitBackend::CompIR_RoundingMode(IRInst inst) {530CONDITIONAL_DISABLE;531532switch (inst.op) {533case IROp::RestoreRoundingMode:534RestoreRoundingMode();535break;536537case IROp::ApplyRoundingMode:538ApplyRoundingMode();539break;540541case IROp::UpdateRoundingMode:542// Do nothing, we don't use any instructions that need updating the rounding mode.543break;544545default:546INVALIDOP;547break;548}549}550551void LoongArch64JitBackend::CompIR_FSpecial(IRInst inst) {552CONDITIONAL_DISABLE;553554auto callFuncF_F = [&](float (*func)(float)) {555regs_.FlushBeforeCall();556WriteDebugProfilerStatus(IRProfilerStatus::MATH_HELPER);557558// It might be in a non-volatile register.559// TODO: May have to handle a transfer if SIMD here.560if (regs_.IsFPRMapped(inst.src1)) {561int lane = regs_.GetFPRLane(inst.src1);562if (lane == 0)563FMOV_S(F0, regs_.F(inst.src1));564else565VREPLVEI_W(V0, regs_.V(inst.src1), lane);566} else {567int offset = offsetof(MIPSState, f) + inst.src1 * 4;568FLD_S(F0, CTXREG, offset);569}570QuickCallFunction(func, SCRATCH1);571572regs_.MapFPR(inst.dest, MIPSMap::NOINIT);573// If it's already F0, we're done - MapReg doesn't actually overwrite the reg in that case.574if (regs_.F(inst.dest) != F0) {575FMOV_S(regs_.F(inst.dest), F0);576}577578WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);579};580581switch (inst.op) {582case IROp::FSin:583callFuncF_F(&vfpu_sin);584break;585586case IROp::FCos:587callFuncF_F(&vfpu_cos);588break;589590case IROp::FRSqrt:591regs_.Map(inst);592FRSQRT_S(regs_.F(inst.dest), regs_.F(inst.src1));593break;594595case IROp::FRecip:596regs_.Map(inst);597FRECIP_S(regs_.F(inst.dest), regs_.F(inst.src1));598break;599600case IROp::FAsin:601callFuncF_F(&vfpu_asin);602break;603604default:605INVALIDOP;606break;607}608}609610} // namespace MIPSComp611612