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,
}
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,
SecondaryField fmt,
Register rt,
......@@ -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) {
GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
}
......
......@@ -805,6 +805,7 @@ class Assembler : public AssemblerBase {
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 @@ class Assembler : public AssemblerBase {
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,
......
......@@ -302,6 +302,8 @@ Instruction::Type Instruction::InstructionType() const {
return kRegisterType;
};
break;
case COP1X:
return kRegisterType;
// 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
case REGIMM:
case BEQ:
......
......@@ -216,6 +216,8 @@ const int kImm28Bits = 28;
// 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 @@ enum Opcode {
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 @@ enum SecondaryField {
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
};
......@@ -677,6 +683,10 @@ class Instruction {
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 {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
......
......@@ -350,6 +350,10 @@ int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
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;
......@@ -618,6 +622,15 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
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()) {
case JR:
......
......@@ -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) {
Register scratch = scratch0();
Register result = ToRegister(instr->result());
......
......@@ -1283,8 +1283,22 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
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);
}
......@@ -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) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
......@@ -1324,6 +1347,15 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
}
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());
......
......@@ -135,6 +135,7 @@ class LCodeGen;
V(MathMinMax) \
V(ModI) \
V(MulI) \
V(MultiplyAddD) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
......@@ -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> {
public:
LCmpIDAndBranch(LOperand* left, LOperand* right) {
......@@ -2433,6 +2452,8 @@ class LChunkBuilder BASE_EMBEDDED {
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
private:
enum Status {
UNUSED,
......
......@@ -1760,6 +1760,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
UNIMPLEMENTED_MIPS();
};
break;
case COP1X:
break;
case SPECIAL:
switch (instr->FunctionFieldRaw()) {
case JR:
......@@ -1949,6 +1951,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
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();
......@@ -2210,6 +2213,19 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
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()) {
case JR: {
......
......@@ -276,6 +276,8 @@ TEST(MIPS3) {
double e;
double f;
double g;
double h;
double i;
} T;
T t;
......@@ -312,6 +314,13 @@ TEST(MIPS3) {
__ 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 @@ TEST(MIPS3) {
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 @@ TEST(MIPS3) {
CHECK_EQ(1.8066e16, t.e);
CHECK_EQ(120.44, t.f);
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