MIPS: Implement MADD.S, MSUB, MADDF and MSUBF.

Implementation MADD.S. MSUB.fmt, MADDF.fmt, MSUBF.fmt and corresponding
tests for assembler and disassembler.

TEST=cctest/test-assembler-mips[64], cctest/test-disasm-mips[64]
BUG=

Review-Url: https://codereview.chromium.org/2313623002
Cr-Commit-Position: refs/heads/master@{#39415}
This commit is contained in:
Ilija.Pavlovic 2016-09-14 04:36:29 -07:00 committed by Commit bot
parent 3999fb0788
commit 65fd5e1165
14 changed files with 528 additions and 4 deletions

View File

@ -2453,6 +2453,11 @@ void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
}
void Assembler::madd_s(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_S);
}
void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
@ -2460,6 +2465,37 @@ void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
}
void Assembler::msub_s(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1X, fr, ft, fs, fd, MSUB_S);
}
void Assembler::msub_d(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1X, fr, ft, fs, fd, MSUB_D);
}
void Assembler::maddf_s(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrRegister(COP1, S, ft, fs, fd, MADDF_S);
}
void Assembler::maddf_d(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrRegister(COP1, D, ft, fs, fd, MADDF_D);
}
void Assembler::msubf_s(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrRegister(COP1, S, ft, fs, fd, MSUBF_S);
}
void Assembler::msubf_d(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrRegister(COP1, D, ft, fs, fd, MSUBF_D);
}
void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);

View File

@ -878,7 +878,14 @@ class Assembler : public AssemblerBase {
void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_s(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
void madd_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void msub_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void msub_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void maddf_s(FPURegister fd, FPURegister fs, FPURegister ft);
void maddf_d(FPURegister fd, FPURegister fs, FPURegister ft);
void msubf_s(FPURegister fd, FPURegister fs, FPURegister ft);
void msubf_d(FPURegister fd, FPURegister fs, FPURegister ft);
void div_s(FPURegister fd, FPURegister fs, FPURegister ft);
void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
void abs_s(FPURegister fd, FPURegister fs);

View File

@ -525,6 +525,8 @@ enum SecondaryField : uint32_t {
FLOOR_W_S = ((1U << 3) + 7),
RECIP_S = ((2U << 3) + 5),
RSQRT_S = ((2U << 3) + 6),
MADDF_S = ((3U << 3) + 0),
MSUBF_S = ((3U << 3) + 1),
CLASS_S = ((3U << 3) + 3),
CVT_D_S = ((4U << 3) + 1),
CVT_W_S = ((4U << 3) + 4),
@ -550,6 +552,8 @@ enum SecondaryField : uint32_t {
FLOOR_W_D = ((1U << 3) + 7),
RECIP_D = ((2U << 3) + 5),
RSQRT_D = ((2U << 3) + 6),
MADDF_D = ((3U << 3) + 0),
MSUBF_D = ((3U << 3) + 1),
CLASS_D = ((3U << 3) + 3),
MIN = ((3U << 3) + 4),
MINA = ((3U << 3) + 5),
@ -616,8 +620,12 @@ enum SecondaryField : uint32_t {
MOVF = ((2U << 3) + 1), // Function field for MOVT.fmt and MOVF.fmt
SELNEZ_C = ((2U << 3) + 7), // COP1 on FPR registers.
// COP1 Encoding of Function Field When rs=PS.
// COP1X Encoding of Function Field.
MADD_S = ((4U << 3) + 0),
MADD_D = ((4U << 3) + 1),
MSUB_S = ((5U << 3) + 0),
MSUB_D = ((5U << 3) + 1),
// PCREL Encoding of rt Field.
ADDIUPC = ((0U << 2) + 0),

View File

@ -918,6 +918,12 @@ void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
case CVT_D_S:
Format(instr, "cvt.d.'t 'fd, 'fs");
break;
case MADDF_S:
Format(instr, "maddf.s 'fd, 'fs, 'ft");
break;
case MSUBF_S:
Format(instr, "msubf.s 'fd, 'fs, 'ft");
break;
default:
Format(instr, "unknown.cop1.'t");
break;
@ -928,7 +934,17 @@ void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
if (!DecodeTypeRegisterRsType(instr)) {
Format(instr, "unknown.cop1.'t");
switch (instr->FunctionFieldRaw()) {
case MADDF_D:
Format(instr, "maddf.d 'fd, 'fs, 'ft");
break;
case MSUBF_D:
Format(instr, "msubf.d 'fd, 'fs, 'ft");
break;
default:
Format(instr, "unknown.cop1.'t");
break;
}
}
}
@ -1360,9 +1376,18 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
break;
case COP1X:
switch (instr->FunctionFieldRaw()) {
case MADD_S:
Format(instr, "madd.s 'fd, 'fr, 'fs, 'ft");
break;
case MADD_D:
Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
break;
case MSUB_S:
Format(instr, "msub.s 'fd, 'fr, 'fs, 'ft");
break;
case MSUB_D:
Format(instr, "msub.d 'fd, 'fr, 'fs, 'ft");
break;
default:
UNREACHABLE();
}

View File

@ -2482,6 +2482,14 @@ void Simulator::DecodeTypeRegisterDRsType() {
case SUB_D:
set_fpu_register_double(fd_reg(), fs - ft);
break;
case MADDF_D:
DCHECK(IsMipsArchVariant(kMips32r6));
set_fpu_register_double(fd_reg(), fd + (fs * ft));
break;
case MSUBF_D:
DCHECK(IsMipsArchVariant(kMips32r6));
set_fpu_register_double(fd_reg(), fd - (fs * ft));
break;
case MUL_D:
set_fpu_register_double(fd_reg(), fs * ft);
break;
@ -2887,6 +2895,14 @@ void Simulator::DecodeTypeRegisterSRsType() {
case SUB_S:
set_fpu_register_float(fd_reg(), fs - ft);
break;
case MADDF_S:
DCHECK(IsMipsArchVariant(kMips32r6));
set_fpu_register_float(fd_reg(), fd + (fs * ft));
break;
case MSUBF_S:
DCHECK(IsMipsArchVariant(kMips32r6));
set_fpu_register_float(fd_reg(), fd - (fs * ft));
break;
case MUL_S:
set_fpu_register_float(fd_reg(), fs * ft);
break;
@ -3375,13 +3391,42 @@ void Simulator::DecodeTypeRegisterCOP1() {
void Simulator::DecodeTypeRegisterCOP1X() {
switch (get_instr()->FunctionFieldRaw()) {
case MADD_D:
case MADD_S: {
DCHECK(IsMipsArchVariant(kMips32r2));
float fr, ft, fs;
fr = get_fpu_register_float(fr_reg());
fs = get_fpu_register_float(fs_reg());
ft = get_fpu_register_float(ft_reg());
set_fpu_register_float(fd_reg(), fs * ft + fr);
break;
}
case MSUB_S: {
DCHECK(IsMipsArchVariant(kMips32r2));
float fr, ft, fs;
fr = get_fpu_register_float(fr_reg());
fs = get_fpu_register_float(fs_reg());
ft = get_fpu_register_float(ft_reg());
set_fpu_register_float(fd_reg(), fs * ft - fr);
break;
}
case MADD_D: {
DCHECK(IsMipsArchVariant(kMips32r2));
double fr, ft, fs;
fr = get_fpu_register_double(fr_reg());
fs = get_fpu_register_double(fs_reg());
ft = get_fpu_register_double(ft_reg());
set_fpu_register_double(fd_reg(), fs * ft + fr);
break;
}
case MSUB_D: {
DCHECK(IsMipsArchVariant(kMips32r2));
double fr, ft, fs;
fr = get_fpu_register_double(fr_reg());
fs = get_fpu_register_double(fs_reg());
ft = get_fpu_register_double(ft_reg());
set_fpu_register_double(fd_reg(), fs * ft - fr);
break;
}
default:
UNREACHABLE();
}

View File

@ -2780,12 +2780,49 @@ void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
}
void Assembler::madd_s(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_S);
}
void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
}
void Assembler::msub_s(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1X, fr, ft, fs, fd, MSUB_S);
}
void Assembler::msub_d(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1X, fr, ft, fs, fd, MSUB_D);
}
void Assembler::maddf_s(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(COP1, S, ft, fs, fd, MADDF_S);
}
void Assembler::maddf_d(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(COP1, D, ft, fs, fd, MADDF_D);
}
void Assembler::msubf_s(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(COP1, S, ft, fs, fd, MSUBF_S);
}
void Assembler::msubf_d(FPURegister fd, FPURegister fs, FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(COP1, D, ft, fs, fd, MSUBF_D);
}
void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, S, ft, fs, fd, DIV_D);

View File

@ -939,7 +939,14 @@ class Assembler : public AssemblerBase {
void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_s(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
void madd_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void msub_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void msub_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void maddf_s(FPURegister fd, FPURegister fs, FPURegister ft);
void maddf_d(FPURegister fd, FPURegister fs, FPURegister ft);
void msubf_s(FPURegister fd, FPURegister fs, FPURegister ft);
void msubf_d(FPURegister fd, FPURegister fs, FPURegister ft);
void div_s(FPURegister fd, FPURegister fs, FPURegister ft);
void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
void abs_s(FPURegister fd, FPURegister fs);

View File

@ -555,6 +555,8 @@ enum SecondaryField : uint32_t {
FLOOR_W_S = ((1U << 3) + 7),
RECIP_S = ((2U << 3) + 5),
RSQRT_S = ((2U << 3) + 6),
MADDF_S = ((3U << 3) + 0),
MSUBF_S = ((3U << 3) + 1),
CLASS_S = ((3U << 3) + 3),
CVT_D_S = ((4U << 3) + 1),
CVT_W_S = ((4U << 3) + 4),
@ -579,6 +581,8 @@ enum SecondaryField : uint32_t {
FLOOR_W_D = ((1U << 3) + 7),
RECIP_D = ((2U << 3) + 5),
RSQRT_D = ((2U << 3) + 6),
MADDF_D = ((3U << 3) + 0),
MSUBF_D = ((3U << 3) + 1),
CLASS_D = ((3U << 3) + 3),
MIN = ((3U << 3) + 4),
MINA = ((3U << 3) + 5),
@ -646,8 +650,12 @@ enum SecondaryField : uint32_t {
SELNEZ_C = ((2U << 3) + 7), // COP1 on FPR registers.
// COP1 Encoding of Function Field When rs=PS.
// COP1X Encoding of Function Field.
MADD_S = ((4U << 3) + 0),
MADD_D = ((4U << 3) + 1),
MSUB_S = ((5U << 3) + 0),
MSUB_D = ((5U << 3) + 1),
// PCREL Encoding of rt Field.
ADDIUPC = ((0U << 2) + 0),

View File

@ -959,6 +959,12 @@ void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
case CVT_D_S:
Format(instr, "cvt.d.'t 'fd, 'fs");
break;
case MADDF_S:
Format(instr, "maddf.s 'fd, 'fs, 'ft");
break;
case MSUBF_S:
Format(instr, "msubf.s 'fd, 'fs, 'ft");
break;
default:
Format(instr, "unknown.cop1.'t");
break;
@ -969,7 +975,17 @@ void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
if (!DecodeTypeRegisterRsType(instr)) {
Format(instr, "unknown.cop1.'t");
switch (instr->FunctionFieldRaw()) {
case MADDF_D:
Format(instr, "maddf.d 'fd, 'fs, 'ft");
break;
case MSUBF_D:
Format(instr, "msubf.d 'fd, 'fs, 'ft");
break;
default:
Format(instr, "unknown.cop1.'t");
break;
}
}
}
@ -1115,9 +1131,18 @@ void Decoder::DecodeTypeRegisterCOP1(Instruction* instr) {
void Decoder::DecodeTypeRegisterCOP1X(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case MADD_S:
Format(instr, "madd.s 'fd, 'fr, 'fs, 'ft");
break;
case MADD_D:
Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
break;
case MSUB_S:
Format(instr, "msub.s 'fd, 'fr, 'fs, 'ft");
break;
case MSUB_D:
Format(instr, "msub.d 'fd, 'fr, 'fs, 'ft");
break;
default:
UNREACHABLE();
}

View File

@ -2421,6 +2421,14 @@ void Simulator::DecodeTypeRegisterSRsType() {
case SUB_S:
set_fpu_register_float(fd_reg(), fs - ft);
break;
case MADDF_S:
DCHECK(kArchVariant == kMips64r6);
set_fpu_register_float(fd_reg(), fd + (fs * ft));
break;
case MSUBF_S:
DCHECK(kArchVariant == kMips64r6);
set_fpu_register_float(fd_reg(), fd - (fs * ft));
break;
case MUL_S:
set_fpu_register_float(fd_reg(), fs * ft);
break;
@ -2824,6 +2832,14 @@ void Simulator::DecodeTypeRegisterDRsType() {
case SUB_D:
set_fpu_register_double(fd_reg(), fs - ft);
break;
case MADDF_D:
DCHECK(kArchVariant == kMips64r6);
set_fpu_register_double(fd_reg(), fd + (fs * ft));
break;
case MSUBF_D:
DCHECK(kArchVariant == kMips64r6);
set_fpu_register_double(fd_reg(), fd - (fs * ft));
break;
case MUL_D:
set_fpu_register_double(fd_reg(), fs * ft);
break;
@ -3305,13 +3321,42 @@ void Simulator::DecodeTypeRegisterCOP1() {
void Simulator::DecodeTypeRegisterCOP1X() {
switch (get_instr()->FunctionFieldRaw()) {
case MADD_D:
case MADD_S: {
DCHECK(kArchVariant == kMips64r2);
float fr, ft, fs;
fr = get_fpu_register_float(fr_reg());
fs = get_fpu_register_float(fs_reg());
ft = get_fpu_register_float(ft_reg());
set_fpu_register_float(fd_reg(), fs * ft + fr);
break;
}
case MSUB_S: {
DCHECK(kArchVariant == kMips64r2);
float fr, ft, fs;
fr = get_fpu_register_float(fr_reg());
fs = get_fpu_register_float(fs_reg());
ft = get_fpu_register_float(ft_reg());
set_fpu_register_float(fd_reg(), fs * ft - fr);
break;
}
case MADD_D: {
DCHECK(kArchVariant == kMips64r2);
double fr, ft, fs;
fr = get_fpu_register_double(fr_reg());
fs = get_fpu_register_double(fs_reg());
ft = get_fpu_register_double(ft_reg());
set_fpu_register_double(fd_reg(), fs * ft + fr);
break;
}
case MSUB_D: {
DCHECK(kArchVariant == kMips64r2);
double fr, ft, fs;
fr = get_fpu_register_double(fr_reg());
fs = get_fpu_register_double(fs_reg());
ft = get_fpu_register_double(ft_reg());
set_fpu_register_double(fd_reg(), fs * ft - fr);
break;
}
default:
UNREACHABLE();
}

View File

@ -5386,4 +5386,128 @@ TEST(Trampoline) {
CHECK_EQ(res, 0);
}
template <class T>
struct TestCaseMaddMsub {
T fr, fs, ft, fd_add, fd_sub;
};
template <typename T, typename F>
void helper_madd_msub_maddf_msubf(F func) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
T x = std::sqrt(static_cast<T>(2.0));
T y = std::sqrt(static_cast<T>(3.0));
T z = std::sqrt(static_cast<T>(5.0));
T x2 = 11.11, y2 = 22.22, z2 = 33.33;
TestCaseMaddMsub<T> test_cases[] = {
{x, y, z, 0.0, 0.0},
{x, y, -z, 0.0, 0.0},
{x, -y, z, 0.0, 0.0},
{x, -y, -z, 0.0, 0.0},
{-x, y, z, 0.0, 0.0},
{-x, y, -z, 0.0, 0.0},
{-x, -y, z, 0.0, 0.0},
{-x, -y, -z, 0.0, 0.0},
{-3.14, 0.2345, -123.000056, 0.0, 0.0},
{7.3, -23.257, -357.1357, 0.0, 0.0},
{x2, y2, z2, 0.0, 0.0},
{x2, y2, -z2, 0.0, 0.0},
{x2, -y2, z2, 0.0, 0.0},
{x2, -y2, -z2, 0.0, 0.0},
{-x2, y2, z2, 0.0, 0.0},
{-x2, y2, -z2, 0.0, 0.0},
{-x2, -y2, z2, 0.0, 0.0},
{-x2, -y2, -z2, 0.0, 0.0},
};
if (std::is_same<T, float>::value) {
__ lwc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
__ lwc1(f6, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fs)));
__ lwc1(f8, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, ft)));
__ lwc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
} else if (std::is_same<T, double>::value) {
__ ldc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
__ ldc1(f6, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fs)));
__ ldc1(f8, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, ft)));
__ ldc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
} else {
UNREACHABLE();
}
func(assm);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F3 f = FUNCTION_CAST<F3>(code->entry());
const size_t kTableLength = sizeof(test_cases) / sizeof(TestCaseMaddMsub<T>);
TestCaseMaddMsub<T> tc;
for (size_t i = 0; i < kTableLength; i++) {
tc.fr = test_cases[i].fr;
tc.fs = test_cases[i].fs;
tc.ft = test_cases[i].ft;
(CALL_GENERATED_CODE(isolate, f, &tc, 0, 0, 0, 0));
T res_add = tc.fr + (tc.fs * tc.ft);
T res_sub;
if (IsMipsArchVariant(kMips32r2)) {
res_sub = (tc.fs * tc.ft) - tc.fr;
} else if (IsMipsArchVariant(kMips32r6)) {
res_sub = tc.fr - (tc.fs * tc.ft);
}
CHECK_EQ(tc.fd_add, res_add);
CHECK_EQ(tc.fd_sub, res_sub);
}
}
TEST(madd_msub_s) {
if (!IsMipsArchVariant(kMips32r2)) return;
helper_madd_msub_maddf_msubf<float>([](MacroAssembler& assm) {
__ madd_s(f10, f4, f6, f8);
__ swc1(f10, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_add)));
__ msub_s(f16, f4, f6, f8);
__ swc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_sub)));
});
}
TEST(madd_msub_d) {
if (!IsMipsArchVariant(kMips32r2)) return;
helper_madd_msub_maddf_msubf<double>([](MacroAssembler& assm) {
__ madd_d(f10, f4, f6, f8);
__ sdc1(f10, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_add)));
__ msub_d(f16, f4, f6, f8);
__ sdc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_sub)));
});
}
TEST(maddf_msubf_s) {
if (!IsMipsArchVariant(kMips32r6)) return;
helper_madd_msub_maddf_msubf<float>([](MacroAssembler& assm) {
__ maddf_s(f4, f6, f8);
__ swc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_add)));
__ msubf_s(f16, f6, f8);
__ swc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_sub)));
});
}
TEST(maddf_msubf_d) {
if (!IsMipsArchVariant(kMips32r6)) return;
helper_madd_msub_maddf_msubf<double>([](MacroAssembler& assm) {
__ maddf_d(f4, f6, f8);
__ sdc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_add)));
__ msubf_d(f16, f6, f8);
__ sdc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_sub)));
});
}
#undef __

View File

@ -5934,5 +5934,128 @@ TEST(Trampoline) {
CHECK_EQ(res, 0);
}
template <class T>
struct TestCaseMaddMsub {
T fr, fs, ft, fd_add, fd_sub;
};
template <typename T, typename F>
void helper_madd_msub_maddf_msubf(F func) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
T x = std::sqrt(static_cast<T>(2.0));
T y = std::sqrt(static_cast<T>(3.0));
T z = std::sqrt(static_cast<T>(5.0));
T x2 = 11.11, y2 = 22.22, z2 = 33.33;
TestCaseMaddMsub<T> test_cases[] = {
{x, y, z, 0.0, 0.0},
{x, y, -z, 0.0, 0.0},
{x, -y, z, 0.0, 0.0},
{x, -y, -z, 0.0, 0.0},
{-x, y, z, 0.0, 0.0},
{-x, y, -z, 0.0, 0.0},
{-x, -y, z, 0.0, 0.0},
{-x, -y, -z, 0.0, 0.0},
{-3.14, 0.2345, -123.000056, 0.0, 0.0},
{7.3, -23.257, -357.1357, 0.0, 0.0},
{x2, y2, z2, 0.0, 0.0},
{x2, y2, -z2, 0.0, 0.0},
{x2, -y2, z2, 0.0, 0.0},
{x2, -y2, -z2, 0.0, 0.0},
{-x2, y2, z2, 0.0, 0.0},
{-x2, y2, -z2, 0.0, 0.0},
{-x2, -y2, z2, 0.0, 0.0},
{-x2, -y2, -z2, 0.0, 0.0},
};
if (std::is_same<T, float>::value) {
__ lwc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
__ lwc1(f6, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fs)));
__ lwc1(f8, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, ft)));
__ lwc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
} else if (std::is_same<T, double>::value) {
__ ldc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
__ ldc1(f6, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fs)));
__ ldc1(f8, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, ft)));
__ ldc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<T>, fr)));
} else {
UNREACHABLE();
}
func(assm);
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F3 f = FUNCTION_CAST<F3>(code->entry());
const size_t kTableLength = sizeof(test_cases) / sizeof(TestCaseMaddMsub<T>);
TestCaseMaddMsub<T> tc;
for (size_t i = 0; i < kTableLength; i++) {
tc.fr = test_cases[i].fr;
tc.fs = test_cases[i].fs;
tc.ft = test_cases[i].ft;
(CALL_GENERATED_CODE(isolate, f, &tc, 0, 0, 0, 0));
T res_add = tc.fr + (tc.fs * tc.ft);
T res_sub;
if (kArchVariant != kMips64r6) {
res_sub = (tc.fs * tc.ft) - tc.fr;
} else {
res_sub = tc.fr - (tc.fs * tc.ft);
}
CHECK_EQ(tc.fd_add, res_add);
CHECK_EQ(tc.fd_sub, res_sub);
}
}
TEST(madd_msub_s) {
if (kArchVariant == kMips64r6) return;
helper_madd_msub_maddf_msubf<float>([](MacroAssembler& assm) {
__ madd_s(f10, f4, f6, f8);
__ swc1(f10, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_add)));
__ msub_s(f16, f4, f6, f8);
__ swc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_sub)));
});
}
TEST(madd_msub_d) {
if (kArchVariant == kMips64r6) return;
helper_madd_msub_maddf_msubf<double>([](MacroAssembler& assm) {
__ madd_d(f10, f4, f6, f8);
__ sdc1(f10, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_add)));
__ msub_d(f16, f4, f6, f8);
__ sdc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_sub)));
});
}
TEST(maddf_msubf_s) {
if (kArchVariant != kMips64r6) return;
helper_madd_msub_maddf_msubf<float>([](MacroAssembler& assm) {
__ maddf_s(f4, f6, f8);
__ swc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_add)));
__ msubf_s(f16, f6, f8);
__ swc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_sub)));
});
}
TEST(maddf_msubf_d) {
if (kArchVariant != kMips64r6) return;
helper_madd_msub_maddf_msubf<double>([](MacroAssembler& assm) {
__ maddf_d(f4, f6, f8);
__ sdc1(f4, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_add)));
__ msubf_d(f16, f6, f8);
__ sdc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_sub)));
});
}
#undef __

View File

@ -1090,3 +1090,20 @@ TEST(ctc1_cfc1_disasm) {
COMPARE(cfc1(a0, FCSR), "4444f800 cfc1 a0, FCSR");
VERIFY_RUN();
}
TEST(madd_msub_maddf_msubf) {
SET_UP();
if (IsMipsArchVariant(kMips32r2)) {
COMPARE(madd_s(f4, f6, f8, f10), "4cca4120 madd.s f4, f6, f8, f10");
COMPARE(madd_d(f4, f6, f8, f10), "4cca4121 madd.d f4, f6, f8, f10");
COMPARE(msub_s(f4, f6, f8, f10), "4cca4128 msub.s f4, f6, f8, f10");
COMPARE(msub_d(f4, f6, f8, f10), "4cca4129 msub.d f4, f6, f8, f10");
}
if (IsMipsArchVariant(kMips32r6)) {
COMPARE(maddf_s(f4, f8, f10), "460a4118 maddf.s f4, f8, f10");
COMPARE(maddf_d(f4, f8, f10), "462a4118 maddf.d f4, f8, f10");
COMPARE(msubf_s(f4, f8, f10), "460a4119 msubf.s f4, f8, f10");
COMPARE(msubf_d(f4, f8, f10), "462a4119 msubf.d f4, f8, f10");
}
VERIFY_RUN();
}

View File

@ -1276,3 +1276,20 @@ TEST(ctc1_cfc1_disasm) {
COMPARE(cfc1(a0, FCSR), "4444f800 cfc1 a0, FCSR");
VERIFY_RUN();
}
TEST(madd_msub_maddf_msubf) {
SET_UP();
if (kArchVariant == kMips64r2) {
COMPARE(madd_s(f4, f6, f8, f10), "4cca4120 madd.s f4, f6, f8, f10");
COMPARE(madd_d(f4, f6, f8, f10), "4cca4121 madd.d f4, f6, f8, f10");
COMPARE(msub_s(f4, f6, f8, f10), "4cca4128 msub.s f4, f6, f8, f10");
COMPARE(msub_d(f4, f6, f8, f10), "4cca4129 msub.d f4, f6, f8, f10");
}
if (kArchVariant == kMips64r6) {
COMPARE(maddf_s(f4, f8, f10), "460a4118 maddf.s f4, f8, f10");
COMPARE(maddf_d(f4, f8, f10), "462a4118 maddf.d f4, f8, f10");
COMPARE(msubf_s(f4, f8, f10), "460a4119 msubf.s f4, f8, f10");
COMPARE(msubf_d(f4, f8, f10), "462a4119 msubf.d f4, f8, f10");
}
VERIFY_RUN();
}