Revision: 13342
Author: [email protected]
Date: Wed Jan 9 04:31:34 2013
Log: 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 <[email protected]>.
http://code.google.com/p/v8/source/detail?r=13342
Modified:
/branches/bleeding_edge/src/mips/assembler-mips.cc
/branches/bleeding_edge/src/mips/assembler-mips.h
/branches/bleeding_edge/src/mips/constants-mips.cc
/branches/bleeding_edge/src/mips/constants-mips.h
/branches/bleeding_edge/src/mips/disasm-mips.cc
/branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
/branches/bleeding_edge/src/mips/lithium-mips.cc
/branches/bleeding_edge/src/mips/lithium-mips.h
/branches/bleeding_edge/src/mips/simulator-mips.cc
/branches/bleeding_edge/test/cctest/test-assembler-mips.cc
=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips.cc Mon Jan 7 07:02:56
2013
+++ /branches/bleeding_edge/src/mips/assembler-mips.cc Wed Jan 9 04:31:34
2013
@@ -873,6 +873,20 @@
| (fd.code() << kFdShift) | func;
emit(instr);
}
+
+
+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,
@@ -1678,6 +1692,12 @@
void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips.h Mon Jan 7 02:18:25
2013
+++ /branches/bleeding_edge/src/mips/assembler-mips.h Wed Jan 9 04:31:34
2013
@@ -805,6 +805,7 @@
void add_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 madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister
ft);
void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
void abs_d(FPURegister fd, FPURegister fs);
void mov_d(FPURegister fd, FPURegister fs);
@@ -1145,6 +1146,13 @@
FPURegister fd,
SecondaryField func = NULLSF);
+ void GenInstrRegister(Opcode opcode,
+ FPURegister fr,
+ FPURegister ft,
+ FPURegister fs,
+ FPURegister fd,
+ SecondaryField func = NULLSF);
+
void GenInstrRegister(Opcode opcode,
SecondaryField fmt,
Register rt,
=======================================
--- /branches/bleeding_edge/src/mips/constants-mips.cc Mon Jan 16 04:38:59
2012
+++ /branches/bleeding_edge/src/mips/constants-mips.cc Wed Jan 9 04:31:34
2013
@@ -302,6 +302,8 @@
return kRegisterType;
};
break;
+ case COP1X:
+ return kRegisterType;
// 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
case REGIMM:
case BEQ:
=======================================
--- /branches/bleeding_edge/src/mips/constants-mips.h Wed Jan 9 01:40:00
2013
+++ /branches/bleeding_edge/src/mips/constants-mips.h Wed Jan 9 04:31:34
2013
@@ -216,6 +216,8 @@
// and are therefore shifted by 2.
const int kImmFieldShift = 2;
+const int kFrBits = 5;
+const int kFrShift = 21;
const int kFsShift = 11;
const int kFsBits = 5;
const int kFtShift = 16;
@@ -295,7 +297,9 @@
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
- SDC1 = ((7 << 3) + 5) << kOpcodeShift
+ SDC1 = ((7 << 3) + 5) << kOpcodeShift,
+
+ COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
@@ -416,6 +420,8 @@
CVT_S_L = ((4 << 3) + 0),
CVT_D_L = ((4 << 3) + 1),
// COP1 Encoding of Function Field When rs=PS.
+ // COP1X Encoding of Function Field.
+ MADD_D = ((4 << 3) + 1),
NULLSF = 0
};
@@ -676,6 +682,10 @@
inline int FtValue() const {
return Bits(kFtShift + kFtBits - 1, kFtShift);
}
+
+ inline int FrValue() const {
+ return Bits(kFrShift + kFrBits -1, kFrShift);
+ }
// Float Compare condition code instruction bits.
inline int FCccValue() const {
=======================================
--- /branches/bleeding_edge/src/mips/disasm-mips.cc Tue Mar 13 09:18:30 2012
+++ /branches/bleeding_edge/src/mips/disasm-mips.cc Wed Jan 9 04:31:34 2013
@@ -350,6 +350,10 @@
int reg = instr->FdValue();
PrintFPURegister(reg);
return 2;
+ } else if (format[1] == 'r') { // 'fr: fr register.
+ int reg = instr->FrValue();
+ PrintFPURegister(reg);
+ return 2;
}
UNREACHABLE();
return -1;
@@ -617,6 +621,15 @@
default:
UNREACHABLE();
}
+ break;
+ case COP1X:
+ switch (instr->FunctionFieldRaw()) {
+ case MADD_D:
+ Format(instr, "madd.d 'fd, 'fr, 'fs, 'ft");
+ break;
+ default:
+ UNREACHABLE();
+ };
break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Wed Jan 9
02:30:54 2013
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Wed Jan 9
04:31:34 2013
@@ -1141,6 +1141,18 @@
DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg));
__ mflo(result);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.cc Mon Jan 7 02:23:30
2013
+++ /branches/bleeding_edge/src/mips/lithium-mips.cc Wed Jan 9 04:31:34
2013
@@ -1283,8 +1283,22 @@
return DefineAsRegister(mul);
} 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);
-
} else {
return DoArithmeticT(Token::MUL, instr);
}
@@ -1309,6 +1323,15 @@
return DoArithmeticT(Token::SUB, 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) {
@@ -1324,6 +1347,15 @@
}
return result;
} 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);
} else {
ASSERT(instr->representation().IsTagged());
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.h Mon Jan 7 02:18:25 2013
+++ /branches/bleeding_edge/src/mips/lithium-mips.h Wed Jan 9 04:31:34 2013
@@ -135,6 +135,7 @@
V(MathMinMax) \
V(ModI) \
V(MulI) \
+ V(MultiplyAddD) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
@@ -608,6 +609,24 @@
};
+// 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> {
public:
LCmpIDAndBranch(LOperand* left, LOperand* right) {
@@ -2433,6 +2452,8 @@
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
+ LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
+
private:
enum Status {
UNUSED,
=======================================
--- /branches/bleeding_edge/src/mips/simulator-mips.cc Mon Jan 7 07:02:56
2013
+++ /branches/bleeding_edge/src/mips/simulator-mips.cc Wed Jan 9 04:31:34
2013
@@ -1759,6 +1759,8 @@
default:
UNIMPLEMENTED_MIPS();
};
+ break;
+ case COP1X:
break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
@@ -1949,6 +1951,7 @@
const uint32_t rt_u = static_cast<uint32_t>(rt);
const int32_t rd_reg = instr->RdValue();
+ const int32_t fr_reg = instr->FrValue();
const int32_t fs_reg = instr->FsValue();
const int32_t ft_reg = instr->FtValue();
const int32_t fd_reg = instr->FdValue();
@@ -2209,6 +2212,19 @@
default:
UNREACHABLE();
};
+ 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:
switch (instr->FunctionFieldRaw()) {
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-mips.cc Tue Mar 13
09:18:30 2012
+++ /branches/bleeding_edge/test/cctest/test-assembler-mips.cc Wed Jan 9
04:31:34 2013
@@ -276,6 +276,8 @@
double e;
double f;
double g;
+ double h;
+ double i;
} T;
T t;
@@ -312,6 +314,13 @@
__ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
// 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);
__ nop();
@@ -329,6 +338,8 @@
t.d = 0.0;
t.e = 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);
USE(dummy);
CHECK_EQ(1.5e14, t.a);
@@ -338,6 +349,7 @@
CHECK_EQ(1.8066e16, t.e);
CHECK_EQ(120.44, t.f);
CHECK_EQ(10.97451593465515908537, t.g);
+ CHECK_EQ(6.875, t.h);
}
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev