Commit a0fb3677 authored by yangguo@chromium.org's avatar yangguo@chromium.org

MIPS: Emit madd.d for multiply-add on MIPS.

Based on commit r12958 (04586adf).

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/11783049
Patch from Akos Palfi <palfia@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13342 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent aee9febc
...@@ -875,6 +875,20 @@ void Assembler::GenInstrRegister(Opcode opcode, ...@@ -875,6 +875,20 @@ void Assembler::GenInstrRegister(Opcode opcode,
} }
void Assembler::GenInstrRegister(Opcode opcode,
FPURegister fr,
FPURegister ft,
FPURegister fs,
FPURegister fd,
SecondaryField func) {
ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
ASSERT(CpuFeatures::IsEnabled(FPU));
Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
| (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
emit(instr);
}
void Assembler::GenInstrRegister(Opcode opcode, void Assembler::GenInstrRegister(Opcode opcode,
SecondaryField fmt, SecondaryField fmt,
Register rt, Register rt,
...@@ -1680,6 +1694,12 @@ void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) { ...@@ -1680,6 +1694,12 @@ void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
} }
void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft) {
GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
}
void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) { void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, D, ft, fs, fd, DIV_D); GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
} }
......
...@@ -805,6 +805,7 @@ class Assembler : public AssemblerBase { ...@@ -805,6 +805,7 @@ class Assembler : public AssemblerBase {
void add_d(FPURegister fd, FPURegister fs, FPURegister ft); void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
void sub_d(FPURegister fd, FPURegister fs, FPURegister ft); void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_d(FPURegister fd, FPURegister fs, FPURegister ft); void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
void div_d(FPURegister fd, FPURegister fs, FPURegister ft); void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
void abs_d(FPURegister fd, FPURegister fs); void abs_d(FPURegister fd, FPURegister fs);
void mov_d(FPURegister fd, FPURegister fs); void mov_d(FPURegister fd, FPURegister fs);
...@@ -1145,6 +1146,13 @@ class Assembler : public AssemblerBase { ...@@ -1145,6 +1146,13 @@ class Assembler : public AssemblerBase {
FPURegister fd, FPURegister fd,
SecondaryField func = NULLSF); SecondaryField func = NULLSF);
void GenInstrRegister(Opcode opcode,
FPURegister fr,
FPURegister ft,
FPURegister fs,
FPURegister fd,
SecondaryField func = NULLSF);
void GenInstrRegister(Opcode opcode, void GenInstrRegister(Opcode opcode,
SecondaryField fmt, SecondaryField fmt,
Register rt, Register rt,
......
...@@ -302,6 +302,8 @@ Instruction::Type Instruction::InstructionType() const { ...@@ -302,6 +302,8 @@ Instruction::Type Instruction::InstructionType() const {
return kRegisterType; return kRegisterType;
}; };
break; break;
case COP1X:
return kRegisterType;
// 16 bits Immediate type instructions. e.g.: addi dest, src, imm16. // 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
case REGIMM: case REGIMM:
case BEQ: case BEQ:
......
...@@ -216,6 +216,8 @@ const int kImm28Bits = 28; ...@@ -216,6 +216,8 @@ const int kImm28Bits = 28;
// and are therefore shifted by 2. // and are therefore shifted by 2.
const int kImmFieldShift = 2; const int kImmFieldShift = 2;
const int kFrBits = 5;
const int kFrShift = 21;
const int kFsShift = 11; const int kFsShift = 11;
const int kFsBits = 5; const int kFsBits = 5;
const int kFtShift = 16; const int kFtShift = 16;
...@@ -295,7 +297,9 @@ enum Opcode { ...@@ -295,7 +297,9 @@ enum Opcode {
LDC1 = ((6 << 3) + 5) << kOpcodeShift, LDC1 = ((6 << 3) + 5) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift, SWC1 = ((7 << 3) + 1) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift SDC1 = ((7 << 3) + 5) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
}; };
enum SecondaryField { enum SecondaryField {
...@@ -416,6 +420,8 @@ enum SecondaryField { ...@@ -416,6 +420,8 @@ enum SecondaryField {
CVT_S_L = ((4 << 3) + 0), CVT_S_L = ((4 << 3) + 0),
CVT_D_L = ((4 << 3) + 1), CVT_D_L = ((4 << 3) + 1),
// COP1 Encoding of Function Field When rs=PS. // COP1 Encoding of Function Field When rs=PS.
// COP1X Encoding of Function Field.
MADD_D = ((4 << 3) + 1),
NULLSF = 0 NULLSF = 0
}; };
...@@ -677,6 +683,10 @@ class Instruction { ...@@ -677,6 +683,10 @@ class Instruction {
return Bits(kFtShift + kFtBits - 1, kFtShift); return Bits(kFtShift + kFtBits - 1, kFtShift);
} }
inline int FrValue() const {
return Bits(kFrShift + kFrBits -1, kFrShift);
}
// Float Compare condition code instruction bits. // Float Compare condition code instruction bits.
inline int FCccValue() const { inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift); return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
......
...@@ -350,6 +350,10 @@ int Decoder::FormatFPURegister(Instruction* instr, const char* format) { ...@@ -350,6 +350,10 @@ int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
int reg = instr->FdValue(); int reg = instr->FdValue();
PrintFPURegister(reg); PrintFPURegister(reg);
return 2; return 2;
} else if (format[1] == 'r') { // 'fr: fr register.
int reg = instr->FrValue();
PrintFPURegister(reg);
return 2;
} }
UNREACHABLE(); UNREACHABLE();
return -1; return -1;
...@@ -618,6 +622,15 @@ void Decoder::DecodeTypeRegister(Instruction* instr) { ...@@ -618,6 +622,15 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
UNREACHABLE(); UNREACHABLE();
} }
break; break;
case COP1X:
switch (instr->FunctionFieldRaw()) {
case MADD_D:
Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
break;
default:
UNREACHABLE();
};
break;
case SPECIAL: case SPECIAL:
switch (instr->FunctionFieldRaw()) { switch (instr->FunctionFieldRaw()) {
case JR: case JR:
......
...@@ -1143,6 +1143,18 @@ void LCodeGen::DoDivI(LDivI* instr) { ...@@ -1143,6 +1143,18 @@ void LCodeGen::DoDivI(LDivI* instr) {
} }
void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
DoubleRegister addend = ToDoubleRegister(instr->addend());
DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
// This is computed in-place.
ASSERT(addend.is(ToDoubleRegister(instr->result())));
__ madd_d(addend, addend, multiplier, multiplicand);
}
void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoMulI(LMulI* instr) {
Register scratch = scratch0(); Register scratch = scratch0();
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
......
...@@ -1283,8 +1283,22 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { ...@@ -1283,8 +1283,22 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
return DefineAsRegister(mul); return DefineAsRegister(mul);
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (kArchVariant == kMips32r2) {
if (instr->UseCount() == 1 && instr->uses().value()->IsAdd()) {
HAdd* add = HAdd::cast(instr->uses().value());
if (instr == add->left()) {
// This mul is the lhs of an add. The add and mul will be folded
// into a multiply-add.
return NULL;
}
if (instr == add->right() && !add->left()->IsMul()) {
// This mul is the rhs of an add, where the lhs is not another mul.
// The add and mul will be folded into a multiply-add.
return NULL;
}
}
}
return DoArithmeticD(Token::MUL, instr); return DoArithmeticD(Token::MUL, instr);
} else { } else {
return DoArithmeticT(Token::MUL, instr); return DoArithmeticT(Token::MUL, instr);
} }
...@@ -1311,6 +1325,15 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { ...@@ -1311,6 +1325,15 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
} }
LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
LOperand* multiplier_op = UseRegisterAtStart(mul->left());
LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
LOperand* addend_op = UseRegisterAtStart(addend);
return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
multiplicand_op));
}
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
if (instr->representation().IsInteger32()) { if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->left()->representation().IsInteger32());
...@@ -1324,6 +1347,15 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { ...@@ -1324,6 +1347,15 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
} }
return result; return result;
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (kArchVariant == kMips32r2) {
if (instr->left()->IsMul())
return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
if (instr->right()->IsMul()) {
ASSERT(!instr->left()->IsMul());
return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
}
}
return DoArithmeticD(Token::ADD, instr); return DoArithmeticD(Token::ADD, instr);
} else { } else {
ASSERT(instr->representation().IsTagged()); ASSERT(instr->representation().IsTagged());
......
...@@ -135,6 +135,7 @@ class LCodeGen; ...@@ -135,6 +135,7 @@ class LCodeGen;
V(MathMinMax) \ V(MathMinMax) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
V(MultiplyAddD) \
V(NumberTagD) \ V(NumberTagD) \
V(NumberTagI) \ V(NumberTagI) \
V(NumberTagU) \ V(NumberTagU) \
...@@ -608,6 +609,24 @@ class LMulI: public LTemplateInstruction<1, 2, 1> { ...@@ -608,6 +609,24 @@ class LMulI: public LTemplateInstruction<1, 2, 1> {
}; };
// Instruction for computing multiplier * multiplicand + addend.
class LMultiplyAddD: public LTemplateInstruction<1, 3, 0> {
public:
LMultiplyAddD(LOperand* addend, LOperand* multiplier,
LOperand* multiplicand) {
inputs_[0] = addend;
inputs_[1] = multiplier;
inputs_[2] = multiplicand;
}
LOperand* addend() { return inputs_[0]; }
LOperand* multiplier() { return inputs_[1]; }
LOperand* multiplicand() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MultiplyAddD, "multiply-add-d")
};
class LCmpIDAndBranch: public LControlInstruction<2, 0> { class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public: public:
LCmpIDAndBranch(LOperand* left, LOperand* right) { LCmpIDAndBranch(LOperand* left, LOperand* right) {
...@@ -2433,6 +2452,8 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -2433,6 +2452,8 @@ class LChunkBuilder BASE_EMBEDDED {
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO #undef DECLARE_DO
LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
private: private:
enum Status { enum Status {
UNUSED, UNUSED,
......
...@@ -1760,6 +1760,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, ...@@ -1760,6 +1760,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
UNIMPLEMENTED_MIPS(); UNIMPLEMENTED_MIPS();
}; };
break; break;
case COP1X:
break;
case SPECIAL: case SPECIAL:
switch (instr->FunctionFieldRaw()) { switch (instr->FunctionFieldRaw()) {
case JR: case JR:
...@@ -1949,6 +1951,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { ...@@ -1949,6 +1951,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
const uint32_t rt_u = static_cast<uint32_t>(rt); const uint32_t rt_u = static_cast<uint32_t>(rt);
const int32_t rd_reg = instr->RdValue(); const int32_t rd_reg = instr->RdValue();
const int32_t fr_reg = instr->FrValue();
const int32_t fs_reg = instr->FsValue(); const int32_t fs_reg = instr->FsValue();
const int32_t ft_reg = instr->FtValue(); const int32_t ft_reg = instr->FtValue();
const int32_t fd_reg = instr->FdValue(); const int32_t fd_reg = instr->FdValue();
...@@ -2210,6 +2213,19 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { ...@@ -2210,6 +2213,19 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
UNREACHABLE(); UNREACHABLE();
}; };
break; break;
case COP1X:
switch (instr->FunctionFieldRaw()) {
case MADD_D:
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();
};
break;
case SPECIAL: case SPECIAL:
switch (instr->FunctionFieldRaw()) { switch (instr->FunctionFieldRaw()) {
case JR: { case JR: {
......
...@@ -276,6 +276,8 @@ TEST(MIPS3) { ...@@ -276,6 +276,8 @@ TEST(MIPS3) {
double e; double e;
double f; double f;
double g; double g;
double h;
double i;
} T; } T;
T t; T t;
...@@ -312,6 +314,13 @@ TEST(MIPS3) { ...@@ -312,6 +314,13 @@ TEST(MIPS3) {
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) ); __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
// g = sqrt(f) = 10.97451593465515908537 // g = sqrt(f) = 10.97451593465515908537
if (kArchVariant == kMips32r2) {
__ ldc1(f4, MemOperand(a0, OFFSET_OF(T, h)) );
__ ldc1(f6, MemOperand(a0, OFFSET_OF(T, i)) );
__ madd_d(f14, f6, f4, f6);
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) );
}
__ jr(ra); __ jr(ra);
__ nop(); __ nop();
...@@ -329,6 +338,8 @@ TEST(MIPS3) { ...@@ -329,6 +338,8 @@ TEST(MIPS3) {
t.d = 0.0; t.d = 0.0;
t.e = 0.0; t.e = 0.0;
t.f = 0.0; t.f = 0.0;
t.h = 1.5;
t.i = 2.75;
Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy); USE(dummy);
CHECK_EQ(1.5e14, t.a); CHECK_EQ(1.5e14, t.a);
...@@ -338,6 +349,7 @@ TEST(MIPS3) { ...@@ -338,6 +349,7 @@ TEST(MIPS3) {
CHECK_EQ(1.8066e16, t.e); CHECK_EQ(1.8066e16, t.e);
CHECK_EQ(120.44, t.f); CHECK_EQ(120.44, t.f);
CHECK_EQ(10.97451593465515908537, t.g); CHECK_EQ(10.97451593465515908537, t.g);
CHECK_EQ(6.875, t.h);
} }
} }
......
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