Commit 6cb0e87c authored by balazs.kilvady's avatar balazs.kilvady Committed by Commit bot

Finish 'MIPS: [turbofan] Add backend support for float32 operations.'

Add missing parts of the port to MIPS/MIPS64 implementations.

BUG=

Review URL: https://codereview.chromium.org/1047213002

Cr-Commit-Position: refs/heads/master@{#27551}
parent 3fbc0cb7
......@@ -787,6 +787,38 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
UNIMPLEMENTED();
static bool convertCondition(FlagsCondition condition, Condition& cc,
bool& acceptNaN) {
acceptNaN = false;
switch (condition) {
case kEqual:
cc = eq;
return true;
case kNotEqual:
cc = ne;
acceptNaN = true;
return true;
case kUnsignedLessThan:
cc = lt;
return true;
case kUnsignedGreaterThanOrEqual:
cc = ge;
acceptNaN = true;
return true;
case kUnsignedLessThanOrEqual:
cc = le;
return true;
case kUnsignedGreaterThan:
cc = gt;
acceptNaN = true;
return true;
default:
break;
}
return false;
}
// Assembles branches after an instruction.
void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
MipsOperandConverter i(this, instr);
......@@ -823,68 +855,24 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
} else if (instr->arch_opcode() == kMipsCmpS) {
// TODO(dusmil) optimize unordered checks to use fewer instructions
// even if we have to unfold BranchF macro.
Label* nan = flabel;
switch (branch->condition) {
case kEqual:
cc = eq;
break;
case kNotEqual:
cc = ne;
nan = tlabel;
break;
case kUnsignedLessThan:
cc = lt;
break;
case kUnsignedGreaterThanOrEqual:
cc = ge;
nan = tlabel;
break;
case kUnsignedLessThanOrEqual:
cc = le;
break;
case kUnsignedGreaterThan:
cc = gt;
nan = tlabel;
break;
default:
UNSUPPORTED_COND(kMipsCmpS, branch->condition);
break;
bool acceptNaN = false;
if (!convertCondition(branch->condition, cc, acceptNaN)) {
UNSUPPORTED_COND(kMips64CmpS, branch->condition);
}
__ BranchFS(tlabel, nan, cc, i.InputDoubleRegister(0),
i.InputDoubleRegister(1));
Label* nan = acceptNaN ? tlabel : flabel;
__ BranchFS(tlabel, nan, cc, i.InputSingleRegister(0),
i.InputSingleRegister(1));
if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel.
} else if (instr->arch_opcode() == kMipsCmpD) {
// TODO(dusmil) optimize unordered checks to use fewer instructions
// even if we have to unfold BranchF macro.
Label* nan = flabel;
switch (branch->condition) {
case kEqual:
cc = eq;
break;
case kNotEqual:
cc = ne;
nan = tlabel;
break;
case kUnsignedLessThan:
cc = lt;
break;
case kUnsignedGreaterThanOrEqual:
cc = ge;
nan = tlabel;
break;
case kUnsignedLessThanOrEqual:
cc = le;
break;
case kUnsignedGreaterThan:
cc = gt;
nan = tlabel;
break;
default:
UNSUPPORTED_COND(kMipsCmpD, branch->condition);
break;
bool acceptNaN = false;
if (!convertCondition(branch->condition, cc, acceptNaN)) {
UNSUPPORTED_COND(kMips64CmpD, branch->condition);
}
Label* nan = acceptNaN ? tlabel : flabel;
__ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
i.InputDoubleRegister(1));
......
......@@ -855,6 +855,38 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
UNIMPLEMENTED();
static bool convertCondition(FlagsCondition condition, Condition& cc,
bool& acceptNaN) {
acceptNaN = false;
switch (condition) {
case kEqual:
cc = eq;
return true;
case kNotEqual:
cc = ne;
acceptNaN = true;
return true;
case kUnsignedLessThan:
cc = lt;
return true;
case kUnsignedGreaterThanOrEqual:
cc = ge;
acceptNaN = true;
return true;
case kUnsignedLessThanOrEqual:
cc = le;
return true;
case kUnsignedGreaterThan:
cc = gt;
acceptNaN = true;
return true;
default:
break;
}
return false;
}
// Assembles branches after an instruction.
void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
MipsOperandConverter i(this, instr);
......@@ -888,68 +920,24 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
} else if (instr->arch_opcode() == kMips64CmpS) {
// TODO(dusmil) optimize unordered checks to use fewer instructions
// even if we have to unfold BranchF macro.
Label* nan = flabel;
switch (branch->condition) {
case kEqual:
cc = eq;
break;
case kNotEqual:
cc = ne;
nan = tlabel;
break;
case kUnsignedLessThan:
cc = lt;
break;
case kUnsignedGreaterThanOrEqual:
cc = ge;
nan = tlabel;
break;
case kUnsignedLessThanOrEqual:
cc = le;
break;
case kUnsignedGreaterThan:
cc = gt;
nan = tlabel;
break;
default:
UNSUPPORTED_COND(kMips64CmpS, branch->condition);
break;
bool acceptNaN = false;
if (!convertCondition(branch->condition, cc, acceptNaN)) {
UNSUPPORTED_COND(kMips64CmpS, branch->condition);
}
__ BranchFS(tlabel, nan, cc, i.InputDoubleRegister(0),
i.InputDoubleRegister(1));
Label* nan = acceptNaN ? tlabel : flabel;
__ BranchFS(tlabel, nan, cc, i.InputSingleRegister(0),
i.InputSingleRegister(1));
if (!branch->fallthru) __ Branch(flabel); // no fallthru to flabel.
} else if (instr->arch_opcode() == kMips64CmpD) {
// TODO(dusmil) optimize unordered checks to use less instructions
// even if we have to unfold BranchF macro.
Label* nan = flabel;
switch (branch->condition) {
case kEqual:
cc = eq;
break;
case kNotEqual:
cc = ne;
nan = tlabel;
break;
case kUnsignedLessThan:
cc = lt;
break;
case kUnsignedGreaterThanOrEqual:
cc = ge;
nan = tlabel;
break;
case kUnsignedLessThanOrEqual:
cc = le;
break;
case kUnsignedGreaterThan:
cc = gt;
nan = tlabel;
break;
default:
UNSUPPORTED_COND(kMips64CmpD, branch->condition);
break;
bool acceptNaN = false;
if (!convertCondition(branch->condition, cc, acceptNaN)) {
UNSUPPORTED_COND(kMips64CmpD, branch->condition);
}
Label* nan = acceptNaN ? tlabel : flabel;
__ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
i.InputDoubleRegister(1));
......
......@@ -89,6 +89,7 @@ class Decoder {
void PrintXImm21(Instruction* instr);
void PrintXImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
void PrintFormat(Instruction* instr); // For floating format postfix.
// Printing of instruction name.
void PrintInstructionName(Instruction* instr);
......@@ -101,6 +102,8 @@ class Decoder {
// Each of these functions decodes one particular instruction type.
bool DecodeTypeRegisterRsType(Instruction* instr);
void DecodeTypeRegisterSRsType(Instruction* instr);
void DecodeTypeRegisterDRsType(Instruction* instr);
void DecodeTypeRegisterLRsType(Instruction* instr);
void DecodeTypeRegisterSPECIAL(Instruction* instr);
......@@ -295,6 +298,29 @@ void Decoder::PrintCode(Instruction* instr) {
}
void Decoder::PrintFormat(Instruction* instr) {
char formatLetter = ' ';
switch (instr->RsFieldRaw()) {
case S:
formatLetter = 's';
break;
case D:
formatLetter = 'd';
break;
case W:
formatLetter = 'w';
break;
case L:
formatLetter = 'l';
break;
default:
UNREACHABLE();
break;
}
PrintChar(formatLetter);
}
// Printing of instruction name.
void Decoder::PrintInstructionName(Instruction* instr) {
}
......@@ -425,6 +451,9 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
PrintCc(instr);
return 2;
}
case 't':
PrintFormat(instr);
return 1;
}
UNREACHABLE();
return -1;
......@@ -455,83 +484,104 @@ void Decoder::Unknown(Instruction* instr) {
}
void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case ADD_D:
Format(instr, "add.d 'fd, 'fs, 'ft");
Format(instr, "add.'t 'fd, 'fs, 'ft");
break;
case SUB_D:
Format(instr, "sub.d 'fd, 'fs, 'ft");
Format(instr, "sub.'t 'fd, 'fs, 'ft");
break;
case MUL_D:
Format(instr, "mul.d 'fd, 'fs, 'ft");
Format(instr, "mul.'t 'fd, 'fs, 'ft");
break;
case DIV_D:
Format(instr, "div.d 'fd, 'fs, 'ft");
Format(instr, "div.'t 'fd, 'fs, 'ft");
break;
case ABS_D:
Format(instr, "abs.d 'fd, 'fs");
Format(instr, "abs.'t 'fd, 'fs");
break;
case MOV_D:
Format(instr, "mov.d 'fd, 'fs");
Format(instr, "mov.'t 'fd, 'fs");
break;
case NEG_D:
Format(instr, "neg.d 'fd, 'fs");
Format(instr, "neg.'t 'fd, 'fs");
break;
case SQRT_D:
Format(instr, "sqrt.d 'fd, 'fs");
Format(instr, "sqrt.'t 'fd, 'fs");
break;
case CVT_W_D:
Format(instr, "cvt.w.d 'fd, 'fs");
Format(instr, "cvt.w.'t 'fd, 'fs");
break;
case CVT_L_D:
Format(instr, "cvt.l.d 'fd, 'fs");
Format(instr, "cvt.l.'t 'fd, 'fs");
break;
case TRUNC_W_D:
Format(instr, "trunc.w.d 'fd, 'fs");
Format(instr, "trunc.w.'t 'fd, 'fs");
break;
case TRUNC_L_D:
Format(instr, "trunc.l.d 'fd, 'fs");
Format(instr, "trunc.l.'t 'fd, 'fs");
break;
case ROUND_W_D:
Format(instr, "round.w.d 'fd, 'fs");
Format(instr, "round.w.'t 'fd, 'fs");
break;
case FLOOR_W_D:
Format(instr, "floor.w.d 'fd, 'fs");
Format(instr, "floor.w.'t 'fd, 'fs");
break;
case CEIL_W_D:
Format(instr, "ceil.w.d 'fd, 'fs");
Format(instr, "ceil.w.'t 'fd, 'fs");
break;
case CVT_S_D:
Format(instr, "cvt.s.d 'fd, 'fs");
Format(instr, "cvt.s.'t 'fd, 'fs");
break;
case C_F_D:
Format(instr, "c.f.d 'fs, 'ft, 'Cc");
Format(instr, "c.f.'t 'fs, 'ft, 'Cc");
break;
case C_UN_D:
Format(instr, "c.un.d 'fs, 'ft, 'Cc");
Format(instr, "c.un.'t 'fs, 'ft, 'Cc");
break;
case C_EQ_D:
Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
Format(instr, "c.eq.'t 'fs, 'ft, 'Cc");
break;
case C_UEQ_D:
Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
Format(instr, "c.ueq.'t 'fs, 'ft, 'Cc");
break;
case C_OLT_D:
Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
Format(instr, "c.olt.'t 'fs, 'ft, 'Cc");
break;
case C_ULT_D:
Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
Format(instr, "c.ult.'t 'fs, 'ft, 'Cc");
break;
case C_OLE_D:
Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
Format(instr, "c.ole.'t 'fs, 'ft, 'Cc");
break;
case C_ULE_D:
Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
Format(instr, "c.ule.'t 'fs, 'ft, 'Cc");
break;
default:
Format(instr, "unknown.cop1.d");
break;
return false;
}
return true;
}
void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
if (!DecodeTypeRegisterRsType(instr)) {
switch (instr->FunctionFieldRaw()) {
case CVT_D_S:
Format(instr, "cvt.d.'t 'fd, 'fs");
break;
default:
Format(instr, "unknown.cop1.'t");
break;
}
}
}
void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
if (!DecodeTypeRegisterRsType(instr)) {
Format(instr, "unknown.cop1.'t");
}
}
......@@ -832,18 +882,12 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
case MTHC1:
Format(instr, "mthc1 'rt, 'fs");
break;
case S:
DecodeTypeRegisterSRsType(instr);
break;
case D:
DecodeTypeRegisterDRsType(instr);
break;
case S:
switch (instr->FunctionFieldRaw()) {
case CVT_D_S:
Format(instr, "cvt.d.s 'fd, 'fs");
break;
default:
UNIMPLEMENTED_MIPS();
}
break;
case W:
switch (instr->FunctionFieldRaw()) {
case CVT_S_W: // Convert word to float (single).
......
......@@ -89,6 +89,7 @@ class Decoder {
void PrintXImm21(Instruction* instr);
void PrintXImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
void PrintFormat(Instruction* instr); // For floating format postfix.
// Printing of instruction name.
void PrintInstructionName(Instruction* instr);
......@@ -101,6 +102,8 @@ class Decoder {
int DecodeBreakInstr(Instruction* instr);
// Each of these functions decodes one particular instruction type.
bool DecodeTypeRegisterRsType(Instruction* instr);
void DecodeTypeRegisterSRsType(Instruction* instr);
void DecodeTypeRegisterDRsType(Instruction* instr);
void DecodeTypeRegisterLRsType(Instruction* instr);
void DecodeTypeRegisterSPECIAL(Instruction* instr);
......@@ -305,6 +308,29 @@ void Decoder::PrintCode(Instruction* instr) {
}
void Decoder::PrintFormat(Instruction* instr) {
char formatLetter = ' ';
switch (instr->RsFieldRaw()) {
case S:
formatLetter = 's';
break;
case D:
formatLetter = 'd';
break;
case W:
formatLetter = 'w';
break;
case L:
formatLetter = 'l';
break;
default:
UNREACHABLE();
break;
}
PrintChar(formatLetter);
}
// Printing of instruction name.
void Decoder::PrintInstructionName(Instruction* instr) {
}
......@@ -435,6 +461,9 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
PrintCc(instr);
return 2;
}
case 't':
PrintFormat(instr);
return 1;
}
UNREACHABLE();
return -1;
......@@ -489,98 +518,119 @@ int Decoder::DecodeBreakInstr(Instruction* instr) {
}
void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case SELEQZ_C:
Format(instr, "seleqz.D 'ft, 'fs, 'fd");
Format(instr, "seleqz.'t 'ft, 'fs, 'fd");
break;
case SELNEZ_C:
Format(instr, "selnez.D 'ft, 'fs, 'fd");
Format(instr, "selnez.'t 'ft, 'fs, 'fd");
break;
case ADD_D:
Format(instr, "add.d 'fd, 'fs, 'ft");
Format(instr, "add.'t 'fd, 'fs, 'ft");
break;
case SUB_D:
Format(instr, "sub.d 'fd, 'fs, 'ft");
Format(instr, "sub.'t 'fd, 'fs, 'ft");
break;
case MUL_D:
Format(instr, "mul.d 'fd, 'fs, 'ft");
Format(instr, "mul.'t 'fd, 'fs, 'ft");
break;
case DIV_D:
Format(instr, "div.d 'fd, 'fs, 'ft");
Format(instr, "div.'t 'fd, 'fs, 'ft");
break;
case ABS_D:
Format(instr, "abs.d 'fd, 'fs");
Format(instr, "abs.'t 'fd, 'fs");
break;
case MOV_D:
Format(instr, "mov.d 'fd, 'fs");
Format(instr, "mov.'t 'fd, 'fs");
break;
case NEG_D:
Format(instr, "neg.d 'fd, 'fs");
Format(instr, "neg.'t 'fd, 'fs");
break;
case SQRT_D:
Format(instr, "sqrt.d 'fd, 'fs");
Format(instr, "sqrt.'t 'fd, 'fs");
break;
case CVT_W_D:
Format(instr, "cvt.w.d 'fd, 'fs");
Format(instr, "cvt.w.'t 'fd, 'fs");
break;
case CVT_L_D:
Format(instr, "cvt.l.d 'fd, 'fs");
Format(instr, "cvt.l.'t 'fd, 'fs");
break;
case TRUNC_W_D:
Format(instr, "trunc.w.d 'fd, 'fs");
Format(instr, "trunc.w.'t 'fd, 'fs");
break;
case TRUNC_L_D:
Format(instr, "trunc.l.d 'fd, 'fs");
Format(instr, "trunc.l.'t 'fd, 'fs");
break;
case ROUND_W_D:
Format(instr, "round.w.d 'fd, 'fs");
Format(instr, "round.w.'t 'fd, 'fs");
break;
case ROUND_L_D:
Format(instr, "round.l.d 'fd, 'fs");
Format(instr, "round.l.'t 'fd, 'fs");
break;
case FLOOR_W_D:
Format(instr, "floor.w.d 'fd, 'fs");
Format(instr, "floor.w.'t 'fd, 'fs");
break;
case FLOOR_L_D:
Format(instr, "floor.l.d 'fd, 'fs");
Format(instr, "floor.l.'t 'fd, 'fs");
break;
case CEIL_W_D:
Format(instr, "ceil.w.d 'fd, 'fs");
Format(instr, "ceil.w.'t 'fd, 'fs");
break;
case CEIL_L_D:
Format(instr, "ceil.l.d 'fd, 'fs");
Format(instr, "ceil.l.'t 'fd, 'fs");
break;
case CVT_S_D:
Format(instr, "cvt.s.d 'fd, 'fs");
Format(instr, "cvt.s.'t 'fd, 'fs");
break;
case C_F_D:
Format(instr, "c.f.d 'fs, 'ft, 'Cc");
Format(instr, "c.f.'t 'fs, 'ft, 'Cc");
break;
case C_UN_D:
Format(instr, "c.un.d 'fs, 'ft, 'Cc");
Format(instr, "c.un.'t 'fs, 'ft, 'Cc");
break;
case C_EQ_D:
Format(instr, "c.eq.d 'fs, 'ft, 'Cc");
Format(instr, "c.eq.'t 'fs, 'ft, 'Cc");
break;
case C_UEQ_D:
Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
Format(instr, "c.ueq.'t 'fs, 'ft, 'Cc");
break;
case C_OLT_D:
Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
Format(instr, "c.olt.'t 'fs, 'ft, 'Cc");
break;
case C_ULT_D:
Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
Format(instr, "c.ult.'t 'fs, 'ft, 'Cc");
break;
case C_OLE_D:
Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
Format(instr, "c.ole.'t 'fs, 'ft, 'Cc");
break;
case C_ULE_D:
Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
Format(instr, "c.ule.'t 'fs, 'ft, 'Cc");
break;
default:
Format(instr, "unknown.cop1.d");
break;
return false;
}
return true;
}
void Decoder::DecodeTypeRegisterSRsType(Instruction* instr) {
if (!DecodeTypeRegisterRsType(instr)) {
switch (instr->FunctionFieldRaw()) {
case CVT_D_S:
Format(instr, "cvt.d.'t 'fd, 'fs");
break;
default:
Format(instr, "unknown.cop1.'t");
break;
}
}
}
void Decoder::DecodeTypeRegisterDRsType(Instruction* instr) {
if (!DecodeTypeRegisterRsType(instr)) {
Format(instr, "unknown.cop1.'t");
}
}
......@@ -656,6 +706,9 @@ void Decoder::DecodeTypeRegisterCOP1(Instruction* instr) {
case MTHC1:
Format(instr, "mthc1 'rt, 'fs");
break;
case S:
DecodeTypeRegisterSRsType(instr);
break;
case D:
DecodeTypeRegisterDRsType(instr);
break;
......
......@@ -46,6 +46,8 @@ typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
// clang-format off
#define __ assm.
TEST(MIPS16) {
......@@ -347,6 +349,13 @@ TEST(MIPS3) {
double g;
double h;
double i;
float fa;
float fb;
float fc;
float fd;
float fe;
float ff;
float fg;
} T;
T t;
......@@ -355,6 +364,7 @@ TEST(MIPS3) {
MacroAssembler assm(isolate, NULL, 0);
Label L, C;
// Double precision floating point instructions.
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ add_d(f8, f4, f6);
......@@ -387,6 +397,30 @@ TEST(MIPS3) {
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) );
}
// Single precision floating point instructions.
__ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fa)) );
__ lwc1(f6, MemOperand(a0, OFFSET_OF(T, fb)) );
__ add_s(f8, f4, f6);
__ swc1(f8, MemOperand(a0, OFFSET_OF(T, fc)) ); // fc = fa + fb.
__ neg_s(f10, f6); // -fb
__ sub_s(f10, f8, f10);
__ swc1(f10, MemOperand(a0, OFFSET_OF(T, fd)) ); // fd = fc - (-fb).
__ swc1(f4, MemOperand(a0, OFFSET_OF(T, fb)) ); // fb = fa.
__ li(t0, 120);
__ mtc1(t0, f14);
__ cvt_s_w(f14, f14); // f14 = 120.0.
__ mul_s(f10, f10, f14);
__ swc1(f10, MemOperand(a0, OFFSET_OF(T, fe)) ); // fe = fd * 120
__ div_s(f12, f10, f4);
__ swc1(f12, MemOperand(a0, OFFSET_OF(T, ff)) ); // ff = fe / fa
__ sqrt_s(f14, f12);
__ swc1(f14, MemOperand(a0, OFFSET_OF(T, fg)) );
__ jr(ra);
__ nop();
......@@ -395,6 +429,7 @@ TEST(MIPS3) {
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F3 f = FUNCTION_CAST<F3>(code->entry());
// Double test values.
t.a = 1.5e14;
t.b = 2.75e11;
t.c = 0.0;
......@@ -403,8 +438,16 @@ TEST(MIPS3) {
t.f = 0.0;
t.h = 1.5;
t.i = 2.75;
// Single test values.
t.fa = 1.5e6;
t.fb = 2.75e4;
t.fc = 0.0;
t.fd = 0.0;
t.fe = 0.0;
t.ff = 0.0;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
// Expected double results.
CHECK_EQ(1.5e14, t.a);
CHECK_EQ(1.5e14, t.b);
CHECK_EQ(1.50275e14, t.c);
......@@ -415,6 +458,14 @@ TEST(MIPS3) {
if (IsMipsArchVariant(kMips32r2)) {
CHECK_EQ(6.875, t.h);
}
// Expected single results.
CHECK_EQ(1.5e6, t.fa);
CHECK_EQ(1.5e6, t.fb);
CHECK_EQ(1.5275e06, t.fc);
CHECK_EQ(1.5550e06, t.fd);
CHECK_EQ(1.866e08, t.fe);
CHECK_EQ(124.40000152587890625, t.ff);
CHECK_EQ(11.1534748077392578125, t.fg);
}
......
......@@ -45,6 +45,8 @@ typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
// clang-format off
#define __ assm.
......@@ -337,6 +339,13 @@ TEST(MIPS3) {
double g;
double h;
double i;
float fa;
float fb;
float fc;
float fd;
float fe;
float ff;
float fg;
} T;
T t;
......@@ -345,6 +354,7 @@ TEST(MIPS3) {
MacroAssembler assm(isolate, NULL, 0);
Label L, C;
// Double precision floating point instructions.
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
__ add_d(f8, f4, f6);
......@@ -377,6 +387,30 @@ TEST(MIPS3) {
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) );
}
// Single precision floating point instructions.
__ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fa)) );
__ lwc1(f6, MemOperand(a0, OFFSET_OF(T, fb)) );
__ add_s(f8, f4, f6);
__ swc1(f8, MemOperand(a0, OFFSET_OF(T, fc)) ); // fc = fa + fb.
__ neg_s(f10, f6); // -fb
__ sub_s(f10, f8, f10);
__ swc1(f10, MemOperand(a0, OFFSET_OF(T, fd)) ); // fd = fc - (-fb).
__ swc1(f4, MemOperand(a0, OFFSET_OF(T, fb)) ); // fb = fa.
__ li(t0, 120);
__ mtc1(t0, f14);
__ cvt_s_w(f14, f14); // f14 = 120.0.
__ mul_s(f10, f10, f14);
__ swc1(f10, MemOperand(a0, OFFSET_OF(T, fe)) ); // fe = fd * 120
__ div_s(f12, f10, f4);
__ swc1(f12, MemOperand(a0, OFFSET_OF(T, ff)) ); // ff = fe / fa
__ sqrt_s(f14, f12);
__ swc1(f14, MemOperand(a0, OFFSET_OF(T, fg)) );
__ jr(ra);
__ nop();
......@@ -385,6 +419,7 @@ TEST(MIPS3) {
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
F3 f = FUNCTION_CAST<F3>(code->entry());
// Double test values.
t.a = 1.5e14;
t.b = 2.75e11;
t.c = 0.0;
......@@ -393,8 +428,16 @@ TEST(MIPS3) {
t.f = 0.0;
t.h = 1.5;
t.i = 2.75;
// Single test values.
t.fa = 1.5e6;
t.fb = 2.75e4;
t.fc = 0.0;
t.fd = 0.0;
t.fe = 0.0;
t.ff = 0.0;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy);
// Expected double results.
CHECK_EQ(1.5e14, t.a);
CHECK_EQ(1.5e14, t.b);
CHECK_EQ(1.50275e14, t.c);
......@@ -405,6 +448,14 @@ TEST(MIPS3) {
if (kArchVariant == kMips64r2) {
CHECK_EQ(6.875, t.h);
}
// Expected single results.
CHECK_EQ(1.5e6, t.fa);
CHECK_EQ(1.5e6, t.fb);
CHECK_EQ(1.5275e06, t.fc);
CHECK_EQ(1.5550e06, t.fd);
CHECK_EQ(1.866e08, t.fe);
CHECK_EQ(124.40000152587890625, t.ff);
CHECK_EQ(11.1534748077392578125, t.fg);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment