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

Reply via email to