IR: Simplify types. F32 -> U32, F64 -> U64, F128 -> U128
ARM's Architecture Specification Language doesn't distinguish between floats and integers as much as we do. This makes some things difficult to implement. Since our register allocator is now capable of allocating values to XMMs and GPRs as necessary, the Transfer IR instructions are no longer necessary as they used to be and they can be removed.
This commit is contained in:
parent
9a812b0c61
commit
5eb0bdecdf
10 changed files with 150 additions and 226 deletions
|
@ -2351,42 +2351,6 @@ static void FPTwoOp64(BlockOfCode* code, EmitContext& ctx, IR::Inst* inst, void
|
|||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitTransferFromFP32(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.DefineValue(inst, args[0]);
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitTransferFromFP64(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.DefineValue(inst, args[0]);
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitTransferToFP32(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
if (args[0].IsImmediate() && args[0].GetImmediateU32() == 0) {
|
||||
Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||
code->xorps(result, result);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
} else {
|
||||
ctx.reg_alloc.DefineValue(inst, args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitTransferToFP64(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
if (args[0].IsImmediate() && args[0].GetImmediateU64() == 0) {
|
||||
Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||
code->xorps(result, result);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
} else {
|
||||
ctx.reg_alloc.DefineValue(inst, args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitFPAbs32(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
|
|
@ -64,11 +64,7 @@ static size_t GetBitWidth(IR::Type type) {
|
|||
return 32;
|
||||
case IR::Type::U64:
|
||||
return 64;
|
||||
case IR::Type::F32:
|
||||
return 32;
|
||||
case IR::Type::F64:
|
||||
return 64;
|
||||
case IR::Type::F128:
|
||||
case IR::Type::U128:
|
||||
return 128;
|
||||
case IR::Type::NZCVFlags:
|
||||
return 32; // TODO: Update to 16 when flags optimization is done
|
||||
|
|
|
@ -30,13 +30,13 @@ IR::U32 IREmitter::GetRegister(Reg reg) {
|
|||
return Inst<IR::U32>(Opcode::A32GetRegister, IR::Value(reg));
|
||||
}
|
||||
|
||||
IR::F32F64 IREmitter::GetExtendedRegister(ExtReg reg) {
|
||||
IR::U32U64 IREmitter::GetExtendedRegister(ExtReg reg) {
|
||||
if (A32::IsSingleExtReg(reg)) {
|
||||
return Inst<IR::F32F64>(Opcode::A32GetExtendedRegister32, IR::Value(reg));
|
||||
return Inst<IR::U32U64>(Opcode::A32GetExtendedRegister32, IR::Value(reg));
|
||||
}
|
||||
|
||||
if (A32::IsDoubleExtReg(reg)) {
|
||||
return Inst<IR::F32F64>(Opcode::A32GetExtendedRegister64, IR::Value(reg));
|
||||
return Inst<IR::U32U64>(Opcode::A32GetExtendedRegister64, IR::Value(reg));
|
||||
}
|
||||
|
||||
ASSERT_MSG(false, "Invalid reg.");
|
||||
|
@ -47,7 +47,7 @@ void IREmitter::SetRegister(const Reg reg, const IR::U32& value) {
|
|||
Inst(Opcode::A32SetRegister, IR::Value(reg), value);
|
||||
}
|
||||
|
||||
void IREmitter::SetExtendedRegister(const ExtReg reg, const IR::F32F64& value) {
|
||||
void IREmitter::SetExtendedRegister(const ExtReg reg, const IR::U32U64& value) {
|
||||
if (A32::IsSingleExtReg(reg)) {
|
||||
Inst(Opcode::A32SetExtendedRegister32, IR::Value(reg), value);
|
||||
} else if (A32::IsDoubleExtReg(reg)) {
|
||||
|
|
|
@ -34,9 +34,9 @@ public:
|
|||
u32 AlignPC(size_t alignment);
|
||||
|
||||
IR::U32 GetRegister(Reg source_reg);
|
||||
IR::F32F64 GetExtendedRegister(ExtReg source_reg);
|
||||
IR::U32U64 GetExtendedRegister(ExtReg source_reg);
|
||||
void SetRegister(const Reg dest_reg, const IR::U32& value);
|
||||
void SetExtendedRegister(const ExtReg dest_reg, const IR::F32F64& value);
|
||||
void SetExtendedRegister(const ExtReg dest_reg, const IR::U32U64& value);
|
||||
|
||||
void ALUWritePC(const IR::U32& value);
|
||||
void BranchWritePC(const IR::U32& value);
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
namespace Dynarmic {
|
||||
namespace A32 {
|
||||
|
||||
using F32 = IR::F32;
|
||||
using F64 = IR::F64;
|
||||
|
||||
static ExtReg ToExtReg(bool sz, size_t base, bool bit) {
|
||||
if (sz) {
|
||||
return static_cast<ExtReg>(static_cast<size_t>(ExtReg::D0) + base + (bit ? 16 : 0));
|
||||
|
@ -292,13 +289,11 @@ bool ArmTranslatorVisitor::vfp2_VMOV_u32_f64(Cond cond, size_t Vd, Reg t, bool D
|
|||
return UnpredictableInstruction();
|
||||
// VMOV.32 <Dd[0]>, <Rt>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto d_f64 = ir.GetExtendedRegister(d);
|
||||
auto t_u32 = ir.GetRegister(t);
|
||||
auto reg_d = ir.GetExtendedRegister(d);
|
||||
auto reg_t = ir.GetRegister(t);
|
||||
auto result = ir.Pack2x32To1x64(reg_t, ir.MostSignificantWord(reg_d).result);
|
||||
|
||||
auto d_u64 = ir.TransferFromFP64(d_f64);
|
||||
auto result = ir.Pack2x32To1x64(t_u32, ir.MostSignificantWord(d_u64).result);
|
||||
|
||||
ir.SetExtendedRegister(d, ir.TransferToFP64(result));
|
||||
ir.SetExtendedRegister(d, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -309,8 +304,8 @@ bool ArmTranslatorVisitor::vfp2_VMOV_f64_u32(Cond cond, size_t Vn, Reg t, bool N
|
|||
return UnpredictableInstruction();
|
||||
// VMOV.32 <Rt>, <Dn[0]>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n_f64 = ir.GetExtendedRegister(n);
|
||||
ir.SetRegister(t, ir.LeastSignificantWord(ir.TransferFromFP64(n_f64)));
|
||||
auto reg_n = ir.GetExtendedRegister(n);
|
||||
ir.SetRegister(t, ir.LeastSignificantWord(reg_n));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -321,7 +316,7 @@ bool ArmTranslatorVisitor::vfp2_VMOV_u32_f32(Cond cond, size_t Vn, Reg t, bool N
|
|||
return UnpredictableInstruction();
|
||||
// VMOV <Sn>, <Rt>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.SetExtendedRegister(n, ir.TransferToFP32(ir.GetRegister(t)));
|
||||
ir.SetExtendedRegister(n, ir.GetRegister(t));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -332,7 +327,7 @@ bool ArmTranslatorVisitor::vfp2_VMOV_f32_u32(Cond cond, size_t Vn, Reg t, bool N
|
|||
return UnpredictableInstruction();
|
||||
// VMOV <Rt>, <Sn>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.SetRegister(t, ir.TransferFromFP32(ir.GetExtendedRegister(n)));
|
||||
ir.SetRegister(t, ir.GetExtendedRegister(n));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -343,8 +338,8 @@ bool ArmTranslatorVisitor::vfp2_VMOV_2u32_2f32(Cond cond, Reg t2, Reg t, bool M,
|
|||
return UnpredictableInstruction();
|
||||
// VMOV <Sm>, <Sm1>, <Rt>, <Rt2>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.SetExtendedRegister(m, ir.TransferToFP32(ir.GetRegister(t)));
|
||||
ir.SetExtendedRegister(m+1, ir.TransferToFP32(ir.GetRegister(t2)));
|
||||
ir.SetExtendedRegister(m, ir.GetRegister(t));
|
||||
ir.SetExtendedRegister(m+1, ir.GetRegister(t2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -357,8 +352,8 @@ bool ArmTranslatorVisitor::vfp2_VMOV_2f32_2u32(Cond cond, Reg t2, Reg t, bool M,
|
|||
return UnpredictableInstruction();
|
||||
// VMOV <Rt>, <Rt2>, <Sm>, <Sm1>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.SetRegister(t, ir.TransferFromFP32(ir.GetExtendedRegister(m)));
|
||||
ir.SetRegister(t2, ir.TransferFromFP32(ir.GetExtendedRegister(m+1)));
|
||||
ir.SetRegister(t, ir.GetExtendedRegister(m));
|
||||
ir.SetRegister(t2, ir.GetExtendedRegister(m+1));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -370,7 +365,7 @@ bool ArmTranslatorVisitor::vfp2_VMOV_2u32_f64(Cond cond, Reg t2, Reg t, bool M,
|
|||
// VMOV<c> <Dm>, <Rt>, <Rt2>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto value = ir.Pack2x32To1x64(ir.GetRegister(t), ir.GetRegister(t2));
|
||||
ir.SetExtendedRegister(m, ir.TransferToFP64(value));
|
||||
ir.SetExtendedRegister(m, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -383,7 +378,7 @@ bool ArmTranslatorVisitor::vfp2_VMOV_f64_2u32(Cond cond, Reg t2, Reg t, bool M,
|
|||
return UnpredictableInstruction();
|
||||
// VMOV<c> <Rt>, <Rt2>, <Dm>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto value = ir.TransferFromFP64(ir.GetExtendedRegister(m));
|
||||
auto value = ir.GetExtendedRegister(m);
|
||||
ir.SetRegister(t, ir.LeastSignificantWord(value));
|
||||
ir.SetRegister(t2, ir.MostSignificantWord(value).result);
|
||||
}
|
||||
|
@ -556,11 +551,9 @@ bool ArmTranslatorVisitor::vfp2_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz,
|
|||
if (ConditionPassed(cond)) {
|
||||
auto reg_d = ir.GetExtendedRegister(d);
|
||||
if (sz) {
|
||||
auto zero = ir.TransferToFP64(ir.Imm64(0));
|
||||
ir.FPCompare64(reg_d, zero, exc_on_qnan, true);
|
||||
ir.FPCompare64(reg_d, ir.Imm64(0), exc_on_qnan, true);
|
||||
} else {
|
||||
auto zero = ir.TransferToFP32(ir.Imm32(0));
|
||||
ir.FPCompare32(reg_d, zero, exc_on_qnan, true);
|
||||
ir.FPCompare32(reg_d, ir.Imm32(0), exc_on_qnan, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -615,10 +608,10 @@ bool ArmTranslatorVisitor::vfp2_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm8
|
|||
auto hi = ir.ReadMemory32(address);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
if (ir.current_location.EFlag()) std::swap(lo, hi);
|
||||
ir.SetExtendedRegister(d + i, ir.TransferToFP64(ir.Pack2x32To1x64(lo, hi)));
|
||||
ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(lo, hi));
|
||||
} else {
|
||||
auto res = ir.ReadMemory32(address);
|
||||
ir.SetExtendedRegister(d + i, ir.TransferToFP32(res));
|
||||
ir.SetExtendedRegister(d + i, res);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
}
|
||||
}
|
||||
|
@ -645,16 +638,16 @@ bool ArmTranslatorVisitor::vfp2_VPUSH(Cond cond, bool D, size_t Vd, bool sz, Imm
|
|||
|
||||
for (size_t i = 0; i < regs; ++i) {
|
||||
if (sz) {
|
||||
const auto d_u64 = ir.TransferFromFP64(ir.GetExtendedRegister(d + i));
|
||||
auto lo = ir.LeastSignificantWord(d_u64);
|
||||
auto hi = ir.MostSignificantWord(d_u64).result;
|
||||
const auto reg_d = ir.GetExtendedRegister(d + i);
|
||||
auto lo = ir.LeastSignificantWord(reg_d);
|
||||
auto hi = ir.MostSignificantWord(reg_d).result;
|
||||
if (ir.current_location.EFlag()) std::swap(lo, hi);
|
||||
ir.WriteMemory32(address, lo);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
ir.WriteMemory32(address, hi);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
} else {
|
||||
ir.WriteMemory32(address, ir.TransferFromFP32(ir.GetExtendedRegister(d + i)));
|
||||
ir.WriteMemory32(address, ir.GetExtendedRegister(d + i));
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
}
|
||||
}
|
||||
|
@ -673,9 +666,9 @@ bool ArmTranslatorVisitor::vfp2_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd
|
|||
auto lo = ir.ReadMemory32(address);
|
||||
auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4)));
|
||||
if (ir.current_location.EFlag()) std::swap(lo, hi);
|
||||
ir.SetExtendedRegister(d, ir.TransferToFP64(ir.Pack2x32To1x64(lo, hi)));
|
||||
ir.SetExtendedRegister(d, ir.Pack2x32To1x64(lo, hi));
|
||||
} else {
|
||||
ir.SetExtendedRegister(d, ir.TransferToFP32(ir.ReadMemory32(address)));
|
||||
ir.SetExtendedRegister(d, ir.ReadMemory32(address));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -689,14 +682,14 @@ bool ArmTranslatorVisitor::vfp2_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd
|
|||
auto base = n == Reg::PC ? ir.Imm32(ir.AlignPC(4)) : ir.GetRegister(n);
|
||||
auto address = U ? ir.Add(base, ir.Imm32(imm32)) : ir.Sub(base, ir.Imm32(imm32));
|
||||
if (sz) {
|
||||
auto d_u64 = ir.TransferFromFP64(ir.GetExtendedRegister(d));
|
||||
auto lo = ir.LeastSignificantWord(d_u64);
|
||||
auto hi = ir.MostSignificantWord(d_u64).result;
|
||||
auto reg_d = ir.GetExtendedRegister(d);
|
||||
auto lo = ir.LeastSignificantWord(reg_d);
|
||||
auto hi = ir.MostSignificantWord(reg_d).result;
|
||||
if (ir.current_location.EFlag()) std::swap(lo, hi);
|
||||
ir.WriteMemory32(address, lo);
|
||||
ir.WriteMemory32(ir.Add(address, ir.Imm32(4)), hi);
|
||||
} else {
|
||||
ir.WriteMemory32(address, ir.TransferFromFP32(ir.GetExtendedRegister(d)));
|
||||
ir.WriteMemory32(address, ir.GetExtendedRegister(d));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -725,7 +718,7 @@ bool ArmTranslatorVisitor::vfp2_VSTM_a1(Cond cond, bool p, bool u, bool D, bool
|
|||
if (w)
|
||||
ir.SetRegister(n, u ? ir.Add(address, ir.Imm32(imm32)) : address);
|
||||
for (size_t i = 0; i < regs; i++) {
|
||||
auto value = ir.TransferFromFP64(ir.GetExtendedRegister(d + i));
|
||||
auto value = ir.GetExtendedRegister(d + i);
|
||||
auto word1 = ir.LeastSignificantWord(value);
|
||||
auto word2 = ir.MostSignificantWord(value).result;
|
||||
if (ir.current_location.EFlag()) std::swap(word1, word2);
|
||||
|
@ -761,7 +754,7 @@ bool ArmTranslatorVisitor::vfp2_VSTM_a2(Cond cond, bool p, bool u, bool D, bool
|
|||
if (w)
|
||||
ir.SetRegister(n, u ? ir.Add(address, ir.Imm32(imm32)) : address);
|
||||
for (size_t i = 0; i < regs; i++) {
|
||||
auto word = ir.TransferFromFP32(ir.GetExtendedRegister(d + i));
|
||||
auto word = ir.GetExtendedRegister(d + i);
|
||||
ir.WriteMemory32(address, word);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
}
|
||||
|
@ -797,7 +790,7 @@ bool ArmTranslatorVisitor::vfp2_VLDM_a1(Cond cond, bool p, bool u, bool D, bool
|
|||
auto word2 = ir.ReadMemory32(address);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
if (ir.current_location.EFlag()) std::swap(word1, word2);
|
||||
ir.SetExtendedRegister(d + i, ir.TransferToFP64(ir.Pack2x32To1x64(word1, word2)));
|
||||
ir.SetExtendedRegister(d + i, ir.Pack2x32To1x64(word1, word2));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -828,7 +821,7 @@ bool ArmTranslatorVisitor::vfp2_VLDM_a2(Cond cond, bool p, bool u, bool D, bool
|
|||
for (size_t i = 0; i < regs; i++) {
|
||||
auto word = ir.ReadMemory32(address);
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
ir.SetExtendedRegister(d + i, ir.TransferToFP32(word));
|
||||
ir.SetExtendedRegister(d + i, word);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -604,144 +604,128 @@ U32 IREmitter::PackedSelect(const U32& ge, const U32& a, const U32& b) {
|
|||
return Inst<U32>(Opcode::PackedSelect, ge, a, b);
|
||||
}
|
||||
|
||||
F32 IREmitter::TransferToFP32(const U32& a) {
|
||||
return Inst<F32>(Opcode::TransferToFP32, a);
|
||||
U32 IREmitter::FPAbs32(const U32& a) {
|
||||
return Inst<U32>(Opcode::FPAbs32, a);
|
||||
}
|
||||
|
||||
F64 IREmitter::TransferToFP64(const U64& a) {
|
||||
return Inst<F64>(Opcode::TransferToFP64, a);
|
||||
U64 IREmitter::FPAbs64(const U64& a) {
|
||||
return Inst<U64>(Opcode::FPAbs64, a);
|
||||
}
|
||||
|
||||
U32 IREmitter::TransferFromFP32(const F32& a) {
|
||||
return Inst<U32>(Opcode::TransferFromFP32, a);
|
||||
}
|
||||
|
||||
U64 IREmitter::TransferFromFP64(const F64& a) {
|
||||
return Inst<U64>(Opcode::TransferFromFP64, a);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPAbs32(const F32& a) {
|
||||
return Inst<F32>(Opcode::FPAbs32, a);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPAbs64(const F64& a) {
|
||||
return Inst<F64>(Opcode::FPAbs64, a);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPAdd32(const F32& a, const F32& b, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPAdd32(const U32& a, const U32& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPAdd32, a, b);
|
||||
return Inst<U32>(Opcode::FPAdd32, a, b);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPAdd64(const F64& a, const F64& b, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPAdd64(const U64& a, const U64& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPAdd64, a, b);
|
||||
return Inst<U64>(Opcode::FPAdd64, a, b);
|
||||
}
|
||||
|
||||
void IREmitter::FPCompare32(const F32& a, const F32& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||
void IREmitter::FPCompare32(const U32& a, const U32& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
Inst(Opcode::FPCompare32, a, b, Imm1(exc_on_qnan));
|
||||
}
|
||||
|
||||
void IREmitter::FPCompare64(const F64& a, const F64& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||
void IREmitter::FPCompare64(const U64& a, const U64& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
Inst(Opcode::FPCompare64, a, b, Imm1(exc_on_qnan));
|
||||
}
|
||||
|
||||
F32 IREmitter::FPDiv32(const F32& a, const F32& b, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPDiv32(const U32& a, const U32& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPDiv32, a, b);
|
||||
return Inst<U32>(Opcode::FPDiv32, a, b);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPDiv64(const F64& a, const F64& b, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPDiv64(const U64& a, const U64& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPDiv64, a, b);
|
||||
return Inst<U64>(Opcode::FPDiv64, a, b);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPMul32(const F32& a, const F32& b, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPMul32(const U32& a, const U32& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPMul32, a, b);
|
||||
return Inst<U32>(Opcode::FPMul32, a, b);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPMul64(const F64& a, const F64& b, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPMul64(const U64& a, const U64& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPMul64, a, b);
|
||||
return Inst<U64>(Opcode::FPMul64, a, b);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPNeg32(const F32& a) {
|
||||
return Inst<F32>(Opcode::FPNeg32, a);
|
||||
U32 IREmitter::FPNeg32(const U32& a) {
|
||||
return Inst<U32>(Opcode::FPNeg32, a);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPNeg64(const F64& a) {
|
||||
return Inst<F64>(Opcode::FPNeg64, a);
|
||||
U64 IREmitter::FPNeg64(const U64& a) {
|
||||
return Inst<U64>(Opcode::FPNeg64, a);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPSqrt32(const F32& a) {
|
||||
return Inst<F32>(Opcode::FPSqrt32, a);
|
||||
U32 IREmitter::FPSqrt32(const U32& a) {
|
||||
return Inst<U32>(Opcode::FPSqrt32, a);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPSqrt64(const F64& a) {
|
||||
return Inst<F64>(Opcode::FPSqrt64, a);
|
||||
U64 IREmitter::FPSqrt64(const U64& a) {
|
||||
return Inst<U64>(Opcode::FPSqrt64, a);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPSub32(const F32& a, const F32& b, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPSub32(const U32& a, const U32& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPSub32, a, b);
|
||||
return Inst<U32>(Opcode::FPSub32, a, b);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPSub64(const F64& a, const F64& b, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPSub64(const U64& a, const U64& b, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPSub64, a, b);
|
||||
return Inst<U64>(Opcode::FPSub64, a, b);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPDoubleToSingle(const F64& a, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPDoubleToSingle(const U64& a, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPDoubleToSingle, a);
|
||||
return Inst<U32>(Opcode::FPDoubleToSingle, a);
|
||||
}
|
||||
|
||||
F64 IREmitter::FPSingleToDouble(const F32& a, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPSingleToDouble(const U32& a, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPSingleToDouble, a);
|
||||
return Inst<U64>(Opcode::FPSingleToDouble, a);
|
||||
}
|
||||
|
||||
F32 IREmitter::FPSingleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPSingleToS32(const U32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPSingleToS32, a, Imm1(round_towards_zero));
|
||||
return Inst<U32>(Opcode::FPSingleToS32, a, Imm1(round_towards_zero));
|
||||
}
|
||||
|
||||
F32 IREmitter::FPSingleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPSingleToU32(const U32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPSingleToU32, a, Imm1(round_towards_zero));
|
||||
return Inst<U32>(Opcode::FPSingleToU32, a, Imm1(round_towards_zero));
|
||||
}
|
||||
|
||||
F32 IREmitter::FPDoubleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPDoubleToS32(const U32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPDoubleToS32, a, Imm1(round_towards_zero));
|
||||
return Inst<U32>(Opcode::FPDoubleToS32, a, Imm1(round_towards_zero));
|
||||
}
|
||||
|
||||
F32 IREmitter::FPDoubleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPDoubleToU32(const U32& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPDoubleToU32, a, Imm1(round_towards_zero));
|
||||
return Inst<U32>(Opcode::FPDoubleToU32, a, Imm1(round_towards_zero));
|
||||
}
|
||||
|
||||
F32 IREmitter::FPS32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPS32ToSingle(const U32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPS32ToSingle, a, Imm1(round_to_nearest));
|
||||
return Inst<U32>(Opcode::FPS32ToSingle, a, Imm1(round_to_nearest));
|
||||
}
|
||||
|
||||
F32 IREmitter::FPU32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
U32 IREmitter::FPU32ToSingle(const U32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F32>(Opcode::FPU32ToSingle, a, Imm1(round_to_nearest));
|
||||
return Inst<U32>(Opcode::FPU32ToSingle, a, Imm1(round_to_nearest));
|
||||
}
|
||||
|
||||
F64 IREmitter::FPS32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPS32ToDouble(const U32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPS32ToDouble, a, Imm1(round_to_nearest));
|
||||
return Inst<U64>(Opcode::FPS32ToDouble, a, Imm1(round_to_nearest));
|
||||
}
|
||||
|
||||
F64 IREmitter::FPU32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
U64 IREmitter::FPU32ToDouble(const U32& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||
ASSERT(fpscr_controlled);
|
||||
return Inst<F64>(Opcode::FPU32ToDouble, a, Imm1(round_to_nearest));
|
||||
return Inst<U64>(Opcode::FPU32ToDouble, a, Imm1(round_to_nearest));
|
||||
}
|
||||
|
||||
void IREmitter::Breakpoint() {
|
||||
|
|
|
@ -177,36 +177,32 @@ public:
|
|||
U32 PackedAbsDiffSumS8(const U32& a, const U32& b);
|
||||
U32 PackedSelect(const U32& ge, const U32& a, const U32& b);
|
||||
|
||||
F32 TransferToFP32(const U32& a);
|
||||
F64 TransferToFP64(const U64& a);
|
||||
U32 TransferFromFP32(const F32& a);
|
||||
U64 TransferFromFP64(const F64& a);
|
||||
F32 FPAbs32(const F32& a);
|
||||
F64 FPAbs64(const F64& a);
|
||||
F32 FPAdd32(const F32& a, const F32& b, bool fpscr_controlled);
|
||||
F64 FPAdd64(const F64& a, const F64& b, bool fpscr_controlled);
|
||||
void FPCompare32(const F32& a, const F32& b, bool exc_on_qnan, bool fpscr_controlled);
|
||||
void FPCompare64(const F64& a, const F64& b, bool exc_on_qnan, bool fpscr_controlled);
|
||||
F32 FPDiv32(const F32& a, const F32& b, bool fpscr_controlled);
|
||||
F64 FPDiv64(const F64& a, const F64& b, bool fpscr_controlled);
|
||||
F32 FPMul32(const F32& a, const F32& b, bool fpscr_controlled);
|
||||
F64 FPMul64(const F64& a, const F64& b, bool fpscr_controlled);
|
||||
F32 FPNeg32(const F32& a);
|
||||
F64 FPNeg64(const F64& a);
|
||||
F32 FPSqrt32(const F32& a);
|
||||
F64 FPSqrt64(const F64& a);
|
||||
F32 FPSub32(const F32& a, const F32& b, bool fpscr_controlled);
|
||||
F64 FPSub64(const F64& a, const F64& b, bool fpscr_controlled);
|
||||
F32 FPDoubleToSingle(const F64& a, bool fpscr_controlled);
|
||||
F64 FPSingleToDouble(const F32& a, bool fpscr_controlled);
|
||||
F32 FPSingleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
F32 FPSingleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
F32 FPDoubleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
F32 FPDoubleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
F32 FPS32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
F32 FPU32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
F64 FPS32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
F64 FPU32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
U32 FPAbs32(const U32& a);
|
||||
U64 FPAbs64(const U64& a);
|
||||
U32 FPAdd32(const U32& a, const U32& b, bool fpscr_controlled);
|
||||
U64 FPAdd64(const U64& a, const U64& b, bool fpscr_controlled);
|
||||
void FPCompare32(const U32& a, const U32& b, bool exc_on_qnan, bool fpscr_controlled);
|
||||
void FPCompare64(const U64& a, const U64& b, bool exc_on_qnan, bool fpscr_controlled);
|
||||
U32 FPDiv32(const U32& a, const U32& b, bool fpscr_controlled);
|
||||
U64 FPDiv64(const U64& a, const U64& b, bool fpscr_controlled);
|
||||
U32 FPMul32(const U32& a, const U32& b, bool fpscr_controlled);
|
||||
U64 FPMul64(const U64& a, const U64& b, bool fpscr_controlled);
|
||||
U32 FPNeg32(const U32& a);
|
||||
U64 FPNeg64(const U64& a);
|
||||
U32 FPSqrt32(const U32& a);
|
||||
U64 FPSqrt64(const U64& a);
|
||||
U32 FPSub32(const U32& a, const U32& b, bool fpscr_controlled);
|
||||
U64 FPSub64(const U64& a, const U64& b, bool fpscr_controlled);
|
||||
U32 FPDoubleToSingle(const U64& a, bool fpscr_controlled);
|
||||
U64 FPSingleToDouble(const U32& a, bool fpscr_controlled);
|
||||
U32 FPSingleToS32(const U32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
U32 FPSingleToU32(const U32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
U32 FPDoubleToS32(const U32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
U32 FPDoubleToU32(const U32& a, bool round_towards_zero, bool fpscr_controlled);
|
||||
U32 FPS32ToSingle(const U32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
U32 FPU32ToSingle(const U32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
U64 FPS32ToDouble(const U32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
U64 FPU32ToDouble(const U32& a, bool round_to_nearest, bool fpscr_controlled);
|
||||
|
||||
void Breakpoint();
|
||||
|
||||
|
|
|
@ -43,12 +43,10 @@ enum class Type {
|
|||
U16 = 1 << 7,
|
||||
U32 = 1 << 8,
|
||||
U64 = 1 << 9,
|
||||
F32 = 1 << 10,
|
||||
F64 = 1 << 11,
|
||||
F128 = 1 << 12,
|
||||
CoprocInfo = 1 << 13,
|
||||
NZCVFlags = 1 << 14,
|
||||
Cond = 1 << 15,
|
||||
U128 = 1 << 10,
|
||||
CoprocInfo = 1 << 11,
|
||||
NZCVFlags = 1 << 12,
|
||||
Cond = 1 << 13,
|
||||
};
|
||||
|
||||
constexpr Type operator|(Type a, Type b) {
|
||||
|
|
|
@ -6,11 +6,11 @@ OPCODE(Breakpoint, T::Void,
|
|||
|
||||
// A32 Context getters/setters
|
||||
A32OPC(GetRegister, T::U32, T::A32Reg )
|
||||
A32OPC(GetExtendedRegister32, T::F32, T::A32ExtReg )
|
||||
A32OPC(GetExtendedRegister64, T::F64, T::A32ExtReg )
|
||||
A32OPC(GetExtendedRegister32, T::U32, T::A32ExtReg )
|
||||
A32OPC(GetExtendedRegister64, T::U64, T::A32ExtReg )
|
||||
A32OPC(SetRegister, T::Void, T::A32Reg, T::U32 )
|
||||
A32OPC(SetExtendedRegister32, T::Void, T::A32ExtReg, T::F32 )
|
||||
A32OPC(SetExtendedRegister64, T::Void, T::A32ExtReg, T::F64 )
|
||||
A32OPC(SetExtendedRegister32, T::Void, T::A32ExtReg, T::U32 )
|
||||
A32OPC(SetExtendedRegister64, T::Void, T::A32ExtReg, T::U64 )
|
||||
A32OPC(GetCpsr, T::U32, )
|
||||
A32OPC(SetCpsr, T::Void, T::U32 )
|
||||
A32OPC(SetCpsrNZCV, T::Void, T::U32 )
|
||||
|
@ -150,38 +150,34 @@ OPCODE(PackedAbsDiffSumS8, T::U32, T::U32, T::U32
|
|||
OPCODE(PackedSelect, T::U32, T::U32, T::U32, T::U32 )
|
||||
|
||||
// Floating-point operations
|
||||
OPCODE(TransferToFP32, T::F32, T::U32 )
|
||||
OPCODE(TransferToFP64, T::F64, T::U64 )
|
||||
OPCODE(TransferFromFP32, T::U32, T::F32 )
|
||||
OPCODE(TransferFromFP64, T::U64, T::F64 )
|
||||
OPCODE(FPAbs32, T::F32, T::F32 )
|
||||
OPCODE(FPAbs64, T::F64, T::F64 )
|
||||
OPCODE(FPAdd32, T::F32, T::F32, T::F32 )
|
||||
OPCODE(FPAdd64, T::F64, T::F64, T::F64 )
|
||||
OPCODE(FPCompare32, T::Void, T::F32, T::F32, T::U1 )
|
||||
OPCODE(FPCompare64, T::Void, T::F64, T::F64, T::U1 )
|
||||
OPCODE(FPDiv32, T::F32, T::F32, T::F32 )
|
||||
OPCODE(FPDiv64, T::F64, T::F64, T::F64 )
|
||||
OPCODE(FPMul32, T::F32, T::F32, T::F32 )
|
||||
OPCODE(FPMul64, T::F64, T::F64, T::F64 )
|
||||
OPCODE(FPNeg32, T::F32, T::F32 )
|
||||
OPCODE(FPNeg64, T::F64, T::F64 )
|
||||
OPCODE(FPSqrt32, T::F32, T::F32 )
|
||||
OPCODE(FPSqrt64, T::F64, T::F64 )
|
||||
OPCODE(FPSub32, T::F32, T::F32, T::F32 )
|
||||
OPCODE(FPSub64, T::F64, T::F64, T::F64 )
|
||||
OPCODE(FPAbs32, T::U32, T::U32 )
|
||||
OPCODE(FPAbs64, T::U64, T::U64 )
|
||||
OPCODE(FPAdd32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(FPAdd64, T::U64, T::U64, T::U64 )
|
||||
OPCODE(FPCompare32, T::Void, T::U32, T::U32, T::U1 )
|
||||
OPCODE(FPCompare64, T::Void, T::U64, T::U64, T::U1 )
|
||||
OPCODE(FPDiv32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(FPDiv64, T::U64, T::U64, T::U64 )
|
||||
OPCODE(FPMul32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(FPMul64, T::U64, T::U64, T::U64 )
|
||||
OPCODE(FPNeg32, T::U32, T::U32 )
|
||||
OPCODE(FPNeg64, T::U64, T::U64 )
|
||||
OPCODE(FPSqrt32, T::U32, T::U32 )
|
||||
OPCODE(FPSqrt64, T::U64, T::U64 )
|
||||
OPCODE(FPSub32, T::U32, T::U32, T::U32 )
|
||||
OPCODE(FPSub64, T::U64, T::U64, T::U64 )
|
||||
|
||||
// Floating-point conversions
|
||||
OPCODE(FPSingleToDouble, T::F64, T::F32 )
|
||||
OPCODE(FPDoubleToSingle, T::F32, T::F64 )
|
||||
OPCODE(FPSingleToU32, T::F32, T::F32, T::U1 )
|
||||
OPCODE(FPSingleToS32, T::F32, T::F32, T::U1 )
|
||||
OPCODE(FPDoubleToU32, T::F32, T::F64, T::U1 )
|
||||
OPCODE(FPDoubleToS32, T::F32, T::F64, T::U1 )
|
||||
OPCODE(FPU32ToSingle, T::F32, T::F32, T::U1 )
|
||||
OPCODE(FPS32ToSingle, T::F32, T::F32, T::U1 )
|
||||
OPCODE(FPU32ToDouble, T::F64, T::F32, T::U1 )
|
||||
OPCODE(FPS32ToDouble, T::F64, T::F32, T::U1 )
|
||||
OPCODE(FPSingleToDouble, T::U64, T::U32 )
|
||||
OPCODE(FPDoubleToSingle, T::U32, T::U64 )
|
||||
OPCODE(FPSingleToU32, T::U32, T::U32, T::U1 )
|
||||
OPCODE(FPSingleToS32, T::U32, T::U32, T::U1 )
|
||||
OPCODE(FPDoubleToU32, T::U32, T::U64, T::U1 )
|
||||
OPCODE(FPDoubleToS32, T::U32, T::U64, T::U1 )
|
||||
OPCODE(FPU32ToSingle, T::U32, T::U32, T::U1 )
|
||||
OPCODE(FPS32ToSingle, T::U32, T::U32, T::U1 )
|
||||
OPCODE(FPU32ToDouble, T::U64, T::U32, T::U1 )
|
||||
OPCODE(FPS32ToDouble, T::U64, T::U32, T::U1 )
|
||||
|
||||
// A32 Memory access
|
||||
A32OPC(ClearExclusive, T::Void, )
|
||||
|
|
|
@ -97,12 +97,9 @@ using U8 = TypedValue<Type::U8>;
|
|||
using U16 = TypedValue<Type::U16>;
|
||||
using U32 = TypedValue<Type::U32>;
|
||||
using U64 = TypedValue<Type::U64>;
|
||||
using U128 = TypedValue<Type::U128>;
|
||||
using U32U64 = TypedValue<Type::U32 | Type::U64>;
|
||||
using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>;
|
||||
using F32 = TypedValue<Type::F32>;
|
||||
using F64 = TypedValue<Type::F64>;
|
||||
using F128 = TypedValue<Type::F128>;
|
||||
using F32F64 = TypedValue<Type::F32 | Type::F64>;
|
||||
using NZCV = TypedValue<Type::NZCVFlags>;
|
||||
|
||||
} // namespace IR
|
||||
|
|
Loading…
Reference in a new issue