ARM64: Support sign extend for add and subtract
authormartyn.capewell <martyn.capewell@arm.com>
Tue, 7 Apr 2015 11:34:33 +0000 (04:34 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 7 Apr 2015 11:34:41 +0000 (11:34 +0000)
Support sxtb and sxth extend operators on add and subtract, as we've
done for ubtx/h. This is similar to ARM support for sxtab/h.

BUG=

Review URL: https://codereview.chromium.org/1064813003

Cr-Commit-Position: refs/heads/master@{#27624}

src/compiler/arm64/code-generator-arm64.cc
src/compiler/arm64/instruction-codes-arm64.h
src/compiler/arm64/instruction-selector-arm64.cc
test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc

index f3dcdbd4cfad86ec14b4b7c08f21151dfb6d2d94..2c0e8f5cdc2785a25cbb7110330da36be6969285 100644 (file)
@@ -75,6 +75,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
         return Operand(InputRegister32(index), UXTB);
       case kMode_Operand2_R_UXTH:
         return Operand(InputRegister32(index), UXTH);
+      case kMode_Operand2_R_SXTB:
+        return Operand(InputRegister32(index), SXTB);
+      case kMode_Operand2_R_SXTH:
+        return Operand(InputRegister32(index), SXTH);
       case kMode_MRI:
       case kMode_MRR:
         break;
@@ -99,6 +103,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
         return Operand(InputRegister64(index), UXTB);
       case kMode_Operand2_R_UXTH:
         return Operand(InputRegister64(index), UXTH);
+      case kMode_Operand2_R_SXTB:
+        return Operand(InputRegister64(index), SXTB);
+      case kMode_Operand2_R_SXTH:
+        return Operand(InputRegister64(index), SXTH);
       case kMode_MRI:
       case kMode_MRR:
         break;
@@ -117,6 +125,8 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
       case kMode_Operand2_R_ROR_I:
       case kMode_Operand2_R_UXTB:
       case kMode_Operand2_R_UXTH:
+      case kMode_Operand2_R_SXTB:
+      case kMode_Operand2_R_SXTH:
         break;
       case kMode_MRI:
         *first_index += 2;
index be0981f652d6a80fdb0897b1fbba7e6a8114a8e7..2d473ad1f7c1905f1a1a938f0e4a592599cc39a4 100644 (file)
@@ -141,15 +141,17 @@ namespace compiler {
 // I = immediate (handle, external, int32)
 // MRI = [register + immediate]
 // MRR = [register + register]
-#define TARGET_ADDRESSING_MODE_LIST(V)                      \
-  V(MRI)              /* [%r0 + K] */                       \
-  V(MRR)              /* [%r0 + %r1] */                     \
-  V(Operand2_R_LSL_I) /* %r0 LSL K */                       \
-  V(Operand2_R_LSR_I) /* %r0 LSR K */                       \
-  V(Operand2_R_ASR_I) /* %r0 ASR K */                       \
-  V(Operand2_R_ROR_I) /* %r0 ROR K */                       \
-  V(Operand2_R_UXTB)  /* %r0 UXTB (unsigned extend byte) */ \
-  V(Operand2_R_UXTH)  /* %r0 UXTH (unsigned extend halfword) */
+#define TARGET_ADDRESSING_MODE_LIST(V)                          \
+  V(MRI)              /* [%r0 + K] */                           \
+  V(MRR)              /* [%r0 + %r1] */                         \
+  V(Operand2_R_LSL_I) /* %r0 LSL K */                           \
+  V(Operand2_R_LSR_I) /* %r0 LSR K */                           \
+  V(Operand2_R_ASR_I) /* %r0 ASR K */                           \
+  V(Operand2_R_ROR_I) /* %r0 ROR K */                           \
+  V(Operand2_R_UXTB)  /* %r0 UXTB (unsigned extend byte) */     \
+  V(Operand2_R_UXTH)  /* %r0 UXTH (unsigned extend halfword) */ \
+  V(Operand2_R_SXTB)  /* %r0 SXTB (signed extend byte) */       \
+  V(Operand2_R_SXTH)  /* %r0 SXTH (signed extend halfword) */
 
 }  // namespace internal
 }  // namespace compiler
index baebb1700d1e23a8ccc7d338067f28554480c4a6..053ae8f53da9183022e246f1bf33c39c7b635df8 100644 (file)
@@ -157,17 +157,34 @@ bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
 }
 
 
-bool TryMatchAnyExtend(InstructionSelector* selector, Node* node,
-                       InstructionCode* opcode) {
-  NodeMatcher nm(node);
+bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector,
+                       Node* left_node, Node* right_node,
+                       InstructionOperand* left_op,
+                       InstructionOperand* right_op, InstructionCode* opcode) {
+  NodeMatcher nm(right_node);
+
   if (nm.IsWord32And()) {
-    Int32BinopMatcher m(node);
-    if (m.right().HasValue()) {
-      if (m.right().Value() == 0xff) {
-        *opcode |= AddressingModeField::encode(kMode_Operand2_R_UXTB);
-        return true;
-      } else if (m.right().Value() == 0xffff) {
-        *opcode |= AddressingModeField::encode(kMode_Operand2_R_UXTH);
+    Int32BinopMatcher mright(right_node);
+    if (mright.right().Is(0xff) || mright.right().Is(0xffff)) {
+      int32_t mask = mright.right().Value();
+      *left_op = g->UseRegister(left_node);
+      *right_op = g->UseRegister(mright.left().node());
+      *opcode |= AddressingModeField::encode(
+          (mask == 0xff) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH);
+      return true;
+    }
+  } else if (nm.IsWord32Sar()) {
+    Int32BinopMatcher mright(right_node);
+    if (selector->CanCover(mright.node(), mright.left().node()) &&
+        mright.left().IsWord32Shl()) {
+      Int32BinopMatcher mleft_of_right(mright.left().node());
+      if ((mright.right().Is(16) && mleft_of_right.right().Is(16)) ||
+          (mright.right().Is(24) && mleft_of_right.right().Is(24))) {
+        int32_t shift = mright.right().Value();
+        *left_op = g->UseRegister(left_node);
+        *right_op = g->UseRegister(mleft_of_right.left().node());
+        *opcode |= AddressingModeField::encode(
+            (shift == 24) ? kMode_Operand2_R_SXTB : kMode_Operand2_R_SXTH);
         return true;
       }
     }
@@ -193,35 +210,34 @@ void VisitBinop(InstructionSelector* selector, Node* node,
     is_add_sub = true;
   }
 
-  if (g.CanBeImmediate(m.right().node(), operand_mode)) {
-    inputs[input_count++] = g.UseRegister(m.left().node());
-    inputs[input_count++] = g.UseImmediate(m.right().node());
-  } else if (TryMatchAnyShift(selector, m.right().node(), &opcode,
-                              !is_add_sub)) {
-    Matcher m_shift(m.right().node());
-    inputs[input_count++] = g.UseRegister(m.left().node());
+  Node* left_node = m.left().node();
+  Node* right_node = m.right().node();
+
+  if (g.CanBeImmediate(right_node, operand_mode)) {
+    inputs[input_count++] = g.UseRegister(left_node);
+    inputs[input_count++] = g.UseImmediate(right_node);
+  } else if (is_add_sub &&
+             TryMatchAnyExtend(&g, selector, left_node, right_node, &inputs[0],
+                               &inputs[1], &opcode)) {
+    input_count += 2;
+  } else if (is_add_sub && m.HasProperty(Operator::kCommutative) &&
+             TryMatchAnyExtend(&g, selector, right_node, left_node, &inputs[0],
+                               &inputs[1], &opcode)) {
+    input_count += 2;
+  } else if (TryMatchAnyShift(selector, right_node, &opcode, !is_add_sub)) {
+    Matcher m_shift(right_node);
+    inputs[input_count++] = g.UseRegister(left_node);
     inputs[input_count++] = g.UseRegister(m_shift.left().node());
     inputs[input_count++] = g.UseImmediate(m_shift.right().node());
   } else if (m.HasProperty(Operator::kCommutative) &&
-             TryMatchAnyShift(selector, m.left().node(), &opcode,
-                              !is_add_sub)) {
-    Matcher m_shift(m.left().node());
-    inputs[input_count++] = g.UseRegister(m.right().node());
+             TryMatchAnyShift(selector, left_node, &opcode, !is_add_sub)) {
+    Matcher m_shift(left_node);
+    inputs[input_count++] = g.UseRegister(right_node);
     inputs[input_count++] = g.UseRegister(m_shift.left().node());
     inputs[input_count++] = g.UseImmediate(m_shift.right().node());
-  } else if (is_add_sub &&
-             TryMatchAnyExtend(selector, m.right().node(), &opcode)) {
-    Matcher mright(m.right().node());
-    inputs[input_count++] = g.UseRegister(m.left().node());
-    inputs[input_count++] = g.UseRegister(mright.left().node());
-  } else if (is_add_sub && m.HasProperty(Operator::kCommutative) &&
-             TryMatchAnyExtend(selector, m.left().node(), &opcode)) {
-    Matcher mleft(m.left().node());
-    inputs[input_count++] = g.UseRegister(m.right().node());
-    inputs[input_count++] = g.UseRegister(mleft.left().node());
   } else {
-    inputs[input_count++] = g.UseRegister(m.left().node());
-    inputs[input_count++] = g.UseRegister(m.right().node());
+    inputs[input_count++] = g.UseRegister(left_node);
+    inputs[input_count++] = g.UseRegister(right_node);
   }
 
   if (cont->IsBranch()) {
index fd4766477fbb0d3ce4ae558a8c8ceedd110b84b0..85b08e99ad10579061bb0afefa3a96b49b322319 100644 (file)
@@ -472,7 +472,7 @@ TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
 }
 
 
-TEST_P(InstructionSelectorAddSubTest, ExtendByte) {
+TEST_P(InstructionSelectorAddSubTest, UnsignedExtendByte) {
   const AddSub dpi = GetParam();
   const MachineType type = dpi.mi.machine_type;
   StreamBuilder m(this, type, type, type);
@@ -487,7 +487,7 @@ TEST_P(InstructionSelectorAddSubTest, ExtendByte) {
 }
 
 
-TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) {
+TEST_P(InstructionSelectorAddSubTest, UnsignedExtendHalfword) {
   const AddSub dpi = GetParam();
   const MachineType type = dpi.mi.machine_type;
   StreamBuilder m(this, type, type, type);
@@ -502,6 +502,40 @@ TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) {
 }
 
 
+TEST_P(InstructionSelectorAddSubTest, SignedExtendByte) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.mi.constructor)(
+      m.Parameter(0),
+      m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(24)),
+                  m.Int32Constant(24))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, SignedExtendHalfword) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.mi.constructor)(
+      m.Parameter(0),
+      m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(16)),
+                  m.Int32Constant(16))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+}
+
+
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
                         ::testing::ValuesIn(kAddSubInstructions));
 
@@ -646,7 +680,7 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
 }
 
 
-TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) {
+TEST_F(InstructionSelectorTest, AddUnsignedExtendByteOnLeft) {
   {
     StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
     m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)),
@@ -672,7 +706,7 @@ TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) {
 }
 
 
-TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) {
+TEST_F(InstructionSelectorTest, AddUnsignedExtendHalfwordOnLeft) {
   {
     StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
     m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)),
@@ -698,6 +732,66 @@ TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) {
 }
 
 
+TEST_F(InstructionSelectorTest, AddSignedExtendByteOnLeft) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(
+        m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
+                               m.Int32Constant(24)),
+                   m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64);
+    m.Return(
+        m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
+                               m.Int32Constant(24)),
+                   m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddSignedExtendHalfwordOnLeft) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(
+        m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)),
+                               m.Int32Constant(16)),
+                   m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64);
+    m.Return(
+        m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)),
+                               m.Int32Constant(16)),
+                   m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Data processing controlled branches.