Revision: 24575
Author:   [email protected]
Date:     Tue Oct 14 05:03:04 2014 UTC
Log:      [arm] Add support for SMMLA, SMMLS and SMMUL.

TEST=cctest,unittests
[email protected]

Review URL: https://codereview.chromium.org/648283002
https://code.google.com/p/v8/source/detail?r=24575

Modified:
 /branches/bleeding_edge/src/arm/assembler-arm.cc
 /branches/bleeding_edge/src/arm/assembler-arm.h
 /branches/bleeding_edge/src/arm/disasm-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.cc
 /branches/bleeding_edge/src/base/bits.cc
 /branches/bleeding_edge/src/base/bits.h
 /branches/bleeding_edge/test/cctest/test-assembler-arm.cc
 /branches/bleeding_edge/test/cctest/test-disasm-arm.cc
 /branches/bleeding_edge/test/unittests/base/bits-unittest.cc

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Mon Oct 13 14:41:33 2014 UTC +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Oct 14 05:03:04 2014 UTC
@@ -1571,11 +1571,35 @@
 }


-void Assembler::mul(Register dst, Register src1, Register src2,
-                    SBit s, Condition cond) {
+void Assembler::mul(Register dst, Register src1, Register src2, SBit s,
+                    Condition cond) {
   DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
   // dst goes in bits 16-19 for this instruction!
-  emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
+ emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA,
+                      Condition cond) {
+  DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
+  emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
+       srcA.code() * B12 | src2.code() * B8 | B4 | src1.code());
+}
+
+
+void Assembler::smmls(Register dst, Register src1, Register src2, Register srcA,
+                      Condition cond) {
+  DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
+  emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
+       srcA.code() * B12 | src2.code() * B8 | B7 | B6 | B4 | src1.code());
+}
+
+
+void Assembler::smmul(Register dst, Register src1, Register src2,
+                      Condition cond) {
+  DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
+  emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 |
+       src2.code() * B8 | B4 | src1.code());
 }


=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Mon Oct 13 14:41:33 2014 UTC +++ /branches/bleeding_edge/src/arm/assembler-arm.h Tue Oct 14 05:03:04 2014 UTC
@@ -975,6 +975,14 @@
   void mul(Register dst, Register src1, Register src2,
            SBit s = LeaveCC, Condition cond = al);

+  void smmla(Register dst, Register src1, Register src2, Register srcA,
+             Condition cond = al);
+
+  void smmls(Register dst, Register src1, Register src2, Register srcA,
+             Condition cond = al);
+
+ void smmul(Register dst, Register src1, Register src2, Condition cond = al);
+
   void smlal(Register dstL, Register dstH, Register src1, Register src2,
              SBit s = LeaveCC, Condition cond = al);

=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc Mon Aug 4 11:34:54 2014 UTC +++ /branches/bleeding_edge/src/arm/disasm-arm.cc Tue Oct 14 05:03:04 2014 UTC
@@ -1096,6 +1096,22 @@
       break;
     }
     case db_x: {
+      if (instr->Bits(22, 20) == 0x5) {
+        if (instr->Bits(7, 4) == 0xd) {
+          // SMMLS (in V8 notation matching ARM ISA format)
+          Format(instr, "smmls'cond 'rn, 'rm, 'rs, 'rd");
+          break;
+        }
+        if (instr->Bits(7, 4) == 0x1) {
+          if (instr->Bits(15, 12) == 0xF) {
+            Format(instr, "smmul'cond 'rn, 'rm, 'rs");
+          } else {
+            // SMMLA (in V8 notation matching ARM ISA format)
+            Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
+          }
+          break;
+        }
+      }
       if (FLAG_enable_sudiv) {
         if (instr->Bits(5, 4) == 0x1) {
           if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Oct 13 14:41:33 2014 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Oct 14 05:03:04 2014 UTC
@@ -4071,21 +4071,22 @@
   DCHECK(!dividend.is(ip));
   DCHECK(!result.is(ip));
   base::MagicNumbersForDivision<uint32_t> mag =
-      base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
+      base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
   mov(ip, Operand(mag.multiplier));
-  smull(ip, result, dividend, ip);
-  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
+  bool neg = (mag.multiplier & (1U << 31)) != 0;
   if (divisor > 0 && neg) {
-    add(result, result, Operand(dividend));
-  }
-  if (divisor < 0 && !neg && mag.multiplier > 0) {
-    sub(result, result, Operand(dividend));
+    smmla(result, dividend, ip, dividend);
+  } else {
+    smmul(result, dividend, ip);
+    if (divisor < 0 && !neg && mag.multiplier > 0) {
+      sub(result, result, Operand(dividend));
+    }
   }
   if (mag.shift > 0) mov(result, Operand(result, ASR, mag.shift));
   add(result, result, Operand(dividend, LSR, 31));
 }

-
-} }  // namespace v8::internal
+}  // namespace internal
+}  // namespace v8

 #endif  // V8_TARGET_ARCH_ARM
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Sep 8 09:11:11 2014 UTC +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Oct 14 05:03:04 2014 UTC
@@ -2710,6 +2710,40 @@
       break;
     }
     case db_x: {
+      if (instr->Bits(22, 20) == 0x5) {
+        if (instr->Bits(7, 4) == 0xd) {
+          // SMMLS (in V8 notation matching ARM ISA format)
+          // Format(instr, "smmls'cond 'rn, 'rm, 'rs, 'rd");
+          int rm = instr->RmValue();
+          int32_t rm_val = get_register(rm);
+          int rs = instr->RsValue();
+          int32_t rs_val = get_register(rs);
+          int rd = instr->RdValue();
+          int32_t rd_val = get_register(rd);
+ rn_val = base::bits::SignedMulHighAndSub32(rm_val, rs_val, rd_val);
+          set_register(rn, rn_val);
+          return;
+        }
+        if (instr->Bits(7, 4) == 0x1) {
+          int rm = instr->RmValue();
+          int32_t rm_val = get_register(rm);
+          int rs = instr->RsValue();
+          int32_t rs_val = get_register(rs);
+          if (instr->Bits(15, 12) == 0xF) {
+            // SMMUL (in V8 notation matching ARM ISA format)
+            // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
+            rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
+          } else {
+            // SMMLA (in V8 notation matching ARM ISA format)
+            // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
+            int rd = instr->RdValue();
+            int32_t rd_val = get_register(rd);
+ rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
+          }
+          set_register(rn, rn_val);
+          return;
+        }
+      }
       if (FLAG_enable_sudiv) {
         if (instr->Bits(5, 4) == 0x1) {
           if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
=======================================
--- /branches/bleeding_edge/src/base/bits.cc    Tue Sep  2 13:36:35 2014 UTC
+++ /branches/bleeding_edge/src/base/bits.cc    Tue Oct 14 05:03:04 2014 UTC
@@ -19,6 +19,25 @@
   value = value | (value >> 16);
   return value + 1;
 }
+
+
+int32_t SignedMulHigh32(int32_t lhs, int32_t rhs) {
+ int64_t const value = static_cast<int64_t>(lhs) * static_cast<int64_t>(rhs);
+  return bit_cast<int32_t, uint32_t>(bit_cast<uint64_t>(value) >> 32u);
+}
+
+
+int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc) {
+  return bit_cast<int32_t>(bit_cast<uint32_t>(acc) +
+                           bit_cast<uint32_t>(SignedMulHigh32(lhs, rhs)));
+}
+
+
+int32_t SignedMulHighAndSub32(int32_t lhs, int32_t rhs, int32_t acc) {
+  return bit_cast<int32_t>(bit_cast<uint32_t>(acc) -
+                           bit_cast<uint32_t>(SignedMulHigh32(lhs, rhs)));
+}
+

 }  // namespace bits
 }  // namespace base
=======================================
--- /branches/bleeding_edge/src/base/bits.h     Thu Oct  9 09:18:31 2014 UTC
+++ /branches/bleeding_edge/src/base/bits.h     Tue Oct 14 05:03:04 2014 UTC
@@ -186,6 +186,24 @@
   return ((res ^ lhs) & (res ^ ~rhs) & (1U << 31)) != 0;
 #endif
 }
+
+
+// SignedMulHigh32(lhs, rhs) multiplies two signed 32-bit values |lhs| and
+// |rhs|, extracts the most significant 32 bits of the result, and returns
+// those.
+int32_t SignedMulHigh32(int32_t lhs, int32_t rhs);
+
+
+// SignedMulHighAndAdd32(lhs, rhs, acc) multiplies two signed 32-bit values
+// |lhs| and |rhs|, extracts the most significant 32 bits of the result, and
+// adds the accumulate value |acc|.
+int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc);
+
+
+// SignedMulHighAndAdd32(lhs, rhs, acc) multiplies two signed 32-bit values
+// |lhs| and |rhs|, extracts the most significant 32 bits of the result, and
+// subtracts it from the accumulate value |acc|.
+int32_t SignedMulHighAndSub32(int32_t lhs, int32_t rhs, int32_t acc);

 }  // namespace bits
 }  // namespace base
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Mon Sep 8 09:11:11 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Tue Oct 14 05:03:04 2014 UTC
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#include <iostream>  // NOLINT(readability/streams)
+
 #include "src/v8.h"
 #include "test/cctest/cctest.h"

@@ -34,6 +36,7 @@
 #include "src/factory.h"
 #include "src/ostreams.h"

+using namespace v8::base;
 using namespace v8::internal;


@@ -1495,6 +1498,84 @@
 #undef TEST_SDIV


+TEST(smmla) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmla(r1, r1, r2, r3);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt(), z = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, z, 0);
+    CHECK_EQ(bits::SignedMulHighAndAdd32(x, y, z), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(smmls) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmls(r1, r1, r2, r3);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt(), z = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, z, 0);
+    CHECK_EQ(bits::SignedMulHighAndSub32(x, y, z), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(smmul) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmul(r1, r1, r2);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(bits::SignedMulHigh32(x, y), r);
+    USE(dummy);
+  }
+}
+
+
 TEST(code_relative_offset) {
   // Test extracting the offset of a label from the beginning of the code
   // in a register.
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Tue Jun 3 08:12:43 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Tue Oct 14 05:03:04 2014 UTC
@@ -419,6 +419,15 @@
     COMPARE(uxtb16(r3, Operand(r4, ROR, 8)),
             "e6cf3474       uxtb16 r3, r4, ror #8");
   }
+
+  COMPARE(smmls(r0, r1, r2, r3), "e75032d1       smmls r0, r1, r2, r3");
+  COMPARE(smmls(r10, r9, r8, r7), "e75a78d9       smmls r10, r9, r8, r7");
+
+  COMPARE(smmla(r0, r1, r2, r3), "e7503211       smmla r0, r1, r2, r3");
+  COMPARE(smmla(r10, r9, r8, r7), "e75a7819       smmla r10, r9, r8, r7");
+
+  COMPARE(smmul(r0, r1, r2), "e750f211       smmul r0, r1, r2");
+  COMPARE(smmul(r8, r9, r10), "e758fa19       smmul r8, r9, r10");

   VERIFY_RUN();
 }
=======================================
--- /branches/bleeding_edge/test/unittests/base/bits-unittest.cc Thu Oct 9 09:18:31 2014 UTC +++ /branches/bleeding_edge/test/unittests/base/bits-unittest.cc Tue Oct 14 05:03:04 2014 UTC
@@ -198,6 +198,42 @@
     }
   }
 }
+
+
+TEST(Bits, SignedMulHigh32) {
+  EXPECT_EQ(0, SignedMulHigh32(0, 0));
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+ TRACED_FORRANGE(int32_t, j, 1, i) { EXPECT_EQ(0, SignedMulHigh32(i, j)); }
+  }
+ EXPECT_EQ(-1073741824, SignedMulHigh32(std::numeric_limits<int32_t>::max(), + std::numeric_limits<int32_t>::min())); + EXPECT_EQ(-1073741824, SignedMulHigh32(std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::max()));
+  EXPECT_EQ(1, SignedMulHigh32(1024 * 1024 * 1024, 4));
+  EXPECT_EQ(2, SignedMulHigh32(8 * 1024, 1024 * 1024));
+}
+
+
+TEST(Bits, SignedMulHighAndAdd32) {
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    EXPECT_EQ(i, SignedMulHighAndAdd32(0, 0, i));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(i, SignedMulHighAndAdd32(j, j, i));
+    }
+    EXPECT_EQ(i + 1, SignedMulHighAndAdd32(1024 * 1024 * 1024, 4, i));
+  }
+}
+
+
+TEST(Bits, SignedMulHighAndSub32) {
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    EXPECT_EQ(i, SignedMulHighAndSub32(0, 0, i));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(i, SignedMulHighAndSub32(j, j, i));
+    }
+    EXPECT_EQ(i - 1, SignedMulHighAndSub32(1024 * 1024 * 1024, 4, i));
+  }
+}

 }  // namespace bits
 }  // namespace base

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to