fadd(s), fdiv(s), fmul(s), fsub(s), fsel, frsp, fabs, fmr, fneg, fnmsubs.

This commit is contained in:
Ben Vanik 2013-05-27 04:09:07 -07:00
parent fe6df31280
commit 84fb802166
1 changed files with 344 additions and 30 deletions

View File

@ -18,6 +18,11 @@ using namespace xe::cpu::ppc;
using namespace AsmJit;
// Enable rounding numbers to single precision as required.
// This adds a bunch of work per operation and I'm not sure it's required.
#define ROUND_TO_SINGLE
namespace xe {
namespace cpu {
namespace x64 {
@ -26,33 +31,150 @@ namespace x64 {
// Floating-point arithmetic (A-8)
XEEMITTER(faddx, 0xFC00002A, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frA) + (frB)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.addsd(v, e.fpr_value(i.A.FRB));
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(faddsx, 0xEC00002A, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frA) + (frB)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.addsd(v, e.fpr_value(i.A.FRB));
#if defined(ROUND_TO_SINGLE)
// TODO(benvanik): check rounding mode? etc?
// This converts to a single then back to a double to approximate the
// rounding on the 360.
c.cvtsd2ss(v, v);
c.cvtss2sd(v, v);
#endif // ROUND_TO_SINGLE
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fdivx, 0xFC000024, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- frA / frB
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.divsd(v, e.fpr_value(i.A.FRB));
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fdivsx, 0xEC000024, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- frA / frB
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.divsd(v, e.fpr_value(i.A.FRB));
#if defined(ROUND_TO_SINGLE)
// TODO(benvanik): check rounding mode? etc?
// This converts to a single then back to a double to approximate the
// rounding on the 360.
c.cvtsd2ss(v, v);
c.cvtss2sd(v, v);
#endif // ROUND_TO_SINGLE
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fmulx, 0xFC000032, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frA) x (frC)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.mulsd(v, e.fpr_value(i.A.FRC));
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fmulsx, 0xEC000032, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frA) x (frC)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.mulsd(v, e.fpr_value(i.A.FRC));
#if defined(ROUND_TO_SINGLE)
// TODO(benvanik): check rounding mode? etc?
// This converts to a single then back to a double to approximate the
// rounding on the 360.
c.cvtsd2ss(v, v);
c.cvtss2sd(v, v);
#endif // ROUND_TO_SINGLE
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fresx, 0xEC000030, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
@ -66,18 +188,87 @@ XEEMITTER(frsqrtex, 0xFC000034, A )(X64Emitter& e, X86Compiler& c, InstrDat
}
XEEMITTER(fsubx, 0xFC000028, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frA) - (frB)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.subsd(v, e.fpr_value(i.A.FRB));
#if defined(ROUND_TO_SINGLE)
// TODO(benvanik): check rounding mode? etc?
// This converts to a single then back to a double to approximate the
// rounding on the 360.
c.cvtsd2ss(v, v);
c.cvtss2sd(v, v);
#endif // ROUND_TO_SINGLE
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fsubsx, 0xEC000028, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frA) - (frB)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRA));
c.subsd(v, e.fpr_value(i.A.FRB));
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fselx, 0xFC00002E, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// if (frA) >= 0.0
// then frD <- (frC)
// else frD <- (frB)
XmmVar v(c.newXmmVar());
GpVar zero(c.newGpVar());
c.mov(zero, imm(0));
c.movq(v, zero);
c.cmpsd(e.fpr_value(i.A.FRA), v, 0);
// TODO(benvanik): find a way to do this without jumps.
Label choose_b(c.newLabel());
Label done(c.newLabel());
c.jl(choose_b);
c.movq(v, e.fpr_value(i.A.FRC));
c.jmp(done);
c.bind(choose_b);
c.movq(v, e.fpr_value(i.A.FRB));
c.bind(done);
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fsqrtx, 0xFC00002C, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
@ -124,13 +315,62 @@ XEEMITTER(fnmaddsx, 0xEC00003E, A )(X64Emitter& e, X86Compiler& c, InstrDat
}
XEEMITTER(fnmsubx, 0xFC00003C, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- -([frA x frC] - frB)
XmmVar a_mul_c(c.newXmmVar());
// TODO(benvanik): I'm sure there's an SSE op for this.
// NOTE: we do (frB - [frA x frC]) as that's pretty much the same.
c.movq(a_mul_c, e.fpr_value(i.A.FRA));
c.mulsd(a_mul_c, e.fpr_value(i.A.FRC));
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRB));
c.subsd(v, a_mul_c);
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fnmsubsx, 0xEC00003C, A )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- -([frA x frC] - frB)
XmmVar a_mul_c(c.newXmmVar());
// TODO(benvanik): I'm sure there's an SSE op for this.
// NOTE: we do (frB - [frA x frC]) as that's pretty much the same.
c.movq(a_mul_c, e.fpr_value(i.A.FRA));
c.mulsd(a_mul_c, e.fpr_value(i.A.FRC));
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.A.FRB));
c.subsd(v, a_mul_c);
#if defined(ROUND_TO_SINGLE)
// TODO(benvanik): check rounding mode? etc?
// This converts to a single then back to a double to approximate the
// rounding on the 360.
c.cvtsd2ss(v, v);
c.cvtss2sd(v, v);
#endif // ROUND_TO_SINGLE
e.update_fpr_value(i.A.FRT, v);
// TODO(benvanik): update status/control register.
if (i.A.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
@ -162,8 +402,31 @@ XEEMITTER(fctiwzx, 0xFC00001E, X )(X64Emitter& e, X86Compiler& c, InstrDat
}
XEEMITTER(frspx, 0xFC000018, X )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- Round_single(frB)
#if defined(ROUND_TO_SINGLE)
XmmVar v(c.newXmmVar());
// TODO(benvanik): check rounding mode? etc?
// This converts to a single then back to a double to approximate the
// rounding on the 360.
c.cvtsd2ss(v, e.fpr_value(i.X.RB));
c.cvtss2sd(v, v);
#else
XmmVar v(e.fpr_value(i.X.RB));
#endif // ROUND_TO_SINGLE
e.update_fpr_value(i.X.RT, v);
// TODO(benvanik): update status/control register.
if (i.X.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
@ -229,13 +492,45 @@ XEEMITTER(mtfsfix, 0xFC00010C, X )(X64Emitter& e, X86Compiler& c, InstrDat
// Floating-point move (A-21)
XEEMITTER(fabsx, 0xFC000210, X )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- abs(frB)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.X.RB));
// XOR with 0 in the sign bit and ones everywhere else.
GpVar gp_bit(c.newGpVar());
c.mov(gp_bit, imm(0x7FFFFFFFFFFFFFFF));
XmmVar bit(c.newXmmVar());
c.movq(bit, gp_bit);
c.xorpd(v, bit);
e.update_fpr_value(i.X.RT, v);
if (i.X.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fmrx, 0xFC000090, X )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- (frB)
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.X.RB));
e.update_fpr_value(i.X.RT, v);
if (i.X.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
XEEMITTER(fnabsx, 0xFC000110, X )(X64Emitter& e, X86Compiler& c, InstrData& i) {
@ -244,8 +539,27 @@ XEEMITTER(fnabsx, 0xFC000110, X )(X64Emitter& e, X86Compiler& c, InstrDat
}
XEEMITTER(fnegx, 0xFC000050, X )(X64Emitter& e, X86Compiler& c, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
// frD <- ¬ frB[0] || frB[1-63]
XmmVar v(c.newXmmVar());
c.movq(v, e.fpr_value(i.X.RB));
// XOR with 1 in the sign bit.
GpVar gp_bit(c.newGpVar());
c.mov(gp_bit, imm(0x8000000000000000));
XmmVar bit(c.newXmmVar());
c.movq(bit, gp_bit);
c.xorpd(v, bit);
e.update_fpr_value(i.X.RT, v);
if (i.X.Rc) {
// With cr0 update.
XEASSERTALWAYS();
//e.update_cr_with_cond(0, v);
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}