mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2025-12-26 17:24:57 +01:00
213 lines
6.6 KiB
C++
213 lines
6.6 KiB
C++
/* This file is part of the dynarmic project.
|
|
* Copyright (c) 2018 MerryMage
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
* General Public License version 2 or any later version.
|
|
*/
|
|
|
|
#include <boost/optional.hpp>
|
|
|
|
#include "common/fp/rounding_mode.h"
|
|
#include "frontend/A64/translate/impl/impl.h"
|
|
|
|
namespace Dynarmic::A64 {
|
|
|
|
bool TranslatorVisitor::SCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) {
|
|
const size_t intsize = sf ? 64 : 32;
|
|
const auto fltsize = FPGetDataSize(type);
|
|
if (!fltsize || *fltsize == 16) {
|
|
return UnallocatedEncoding();
|
|
}
|
|
|
|
const IR::U32U64 intval = X(intsize, Rn);
|
|
IR::U32U64 fltval;
|
|
|
|
if (intsize == 32 && *fltsize == 32) {
|
|
fltval = ir.FPS32ToSingle(intval, false, true);
|
|
} else if (intsize == 32 && *fltsize == 64) {
|
|
fltval = ir.FPS32ToDouble(intval, false, true);
|
|
} else if (intsize == 64 && *fltsize == 32) {
|
|
fltval = ir.FPS64ToSingle(intval, false, true);
|
|
} else if (intsize == 64 && *fltsize == 64) {
|
|
fltval = ir.FPS64ToDouble(intval, false, true);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
V_scalar(*fltsize, Vd, fltval);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TranslatorVisitor::UCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) {
|
|
const size_t intsize = sf ? 64 : 32;
|
|
const auto fltsize = FPGetDataSize(type);
|
|
if (!fltsize || *fltsize == 16) {
|
|
return UnallocatedEncoding();
|
|
}
|
|
|
|
const IR::U32U64 intval = X(intsize, Rn);
|
|
IR::U32U64 fltval;
|
|
|
|
if (intsize == 32 && *fltsize == 32) {
|
|
fltval = ir.FPU32ToSingle(intval, false, true);
|
|
} else if (intsize == 32 && *fltsize == 64) {
|
|
fltval = ir.FPU32ToDouble(intval, false, true);
|
|
} else if (intsize == 64 && *fltsize == 32) {
|
|
fltval = ir.FPU64ToSingle(intval, false, true);
|
|
} else if (intsize == 64 && *fltsize == 64) {
|
|
fltval = ir.FPU64ToDouble(intval, false, true);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
V_scalar(*fltsize, Vd, fltval);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TranslatorVisitor::FMOV_float_gen(bool sf, Imm<2> type, Imm<1> rmode_0, Imm<1> opc_0, size_t n, size_t d) {
|
|
// NOTE:
|
|
// opcode<2:1> == 0b11
|
|
// rmode<1> == 0b0
|
|
|
|
const size_t intsize = sf ? 64 : 32;
|
|
size_t fltsize;
|
|
switch (type.ZeroExtend()) {
|
|
case 0b00:
|
|
fltsize = 32;
|
|
break;
|
|
case 0b01:
|
|
fltsize = 64;
|
|
break;
|
|
case 0b10:
|
|
if (rmode_0 != 1) {
|
|
return UnallocatedEncoding();
|
|
}
|
|
fltsize = 128;
|
|
break;
|
|
default:
|
|
case 0b11:
|
|
fltsize = 16;
|
|
return UnallocatedEncoding();
|
|
}
|
|
|
|
bool integer_to_float;
|
|
size_t part;
|
|
switch (rmode_0.ZeroExtend()) {
|
|
case 0b0:
|
|
if (fltsize != 16 && fltsize != intsize) {
|
|
return UnallocatedEncoding();
|
|
}
|
|
integer_to_float = opc_0 == 0b1;
|
|
part = 0;
|
|
break;
|
|
default:
|
|
case 0b1:
|
|
if (intsize != 64 || fltsize != 128) {
|
|
return UnallocatedEncoding();
|
|
}
|
|
integer_to_float = opc_0 == 0b1;
|
|
part = 1;
|
|
fltsize = 64;
|
|
break;
|
|
}
|
|
|
|
if (integer_to_float) {
|
|
IR::U32U64 intval = X(intsize, static_cast<Reg>(n));
|
|
Vpart_scalar(fltsize, static_cast<Vec>(d), part, intval);
|
|
} else {
|
|
IR::UAny fltval = Vpart_scalar(fltsize, static_cast<Vec>(n), part);
|
|
IR::U32U64 intval = ZeroExtend(fltval, intsize);
|
|
X(intsize, static_cast<Reg>(d), intval);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool FloaingPointConvertSignedInteger(TranslatorVisitor& v, bool sf, Imm<2> type, Vec Vn, Reg Rd, FP::RoundingMode rounding_mode) {
|
|
const size_t intsize = sf ? 64 : 32;
|
|
const auto fltsize = FPGetDataSize(type);
|
|
if (!fltsize || *fltsize == 16) {
|
|
return v.UnallocatedEncoding();
|
|
}
|
|
|
|
const IR::U32U64 fltval = v.V_scalar(*fltsize, Vn);
|
|
IR::U32U64 intval;
|
|
|
|
if (intsize == 32) {
|
|
intval = v.ir.FPToFixedS32(fltval, 0, rounding_mode);
|
|
} else if (intsize == 64) {
|
|
intval = v.ir.FPToFixedS64(fltval, 0, rounding_mode);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
v.X(intsize, Rd, intval);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool FloaingPointConvertUnsignedInteger(TranslatorVisitor& v, bool sf, Imm<2> type, Vec Vn, Reg Rd, FP::RoundingMode rounding_mode) {
|
|
const size_t intsize = sf ? 64 : 32;
|
|
const auto fltsize = FPGetDataSize(type);
|
|
if (!fltsize || *fltsize == 16) {
|
|
return v.UnallocatedEncoding();
|
|
}
|
|
|
|
const IR::U32U64 fltval = v.V_scalar(*fltsize, Vn);
|
|
IR::U32U64 intval;
|
|
|
|
if (intsize == 32) {
|
|
intval = v.ir.FPToFixedU32(fltval, 0, rounding_mode);
|
|
} else if (intsize == 64) {
|
|
intval = v.ir.FPToFixedU64(fltval, 0, rounding_mode);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
v.X(intsize, Rd, intval);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTNS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertSignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::ToNearest_TieEven);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTNU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertUnsignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::ToNearest_TieEven);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTZS_float_int(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertSignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::TowardsZero);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTZU_float_int(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertUnsignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::TowardsZero);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTAS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertSignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::ToNearest_TieAwayFromZero);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTAU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertUnsignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::ToNearest_TieAwayFromZero);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTPS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertSignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::TowardsPlusInfinity);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTPU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertUnsignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::TowardsPlusInfinity);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTMS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertSignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::TowardsMinusInfinity);
|
|
}
|
|
|
|
bool TranslatorVisitor::FCVTMU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
|
|
return FloaingPointConvertUnsignedInteger(*this, sf, type, Vn, Rd, FP::RoundingMode::TowardsMinusInfinity);
|
|
}
|
|
|
|
} // namespace Dynarmic::A64
|