[ARM64] [turbofan] Support uxtb/uxth for add/sub.
authorjacob.bramley <jacob.bramley@arm.com>
Thu, 19 Mar 2015 12:44:09 +0000 (05:44 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 19 Mar 2015 12:44:23 +0000 (12:44 +0000)
Add support for appending extend modes uxtb or uxth to add and subtract
instructions, and using them in the instruction selector.

BUG=

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

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

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 fa821f5..b494090 100644 (file)
@@ -71,6 +71,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
         return Operand(InputRegister32(index), ASR, InputInt5(index + 1));
       case kMode_Operand2_R_ROR_I:
         return Operand(InputRegister32(index), ROR, InputInt5(index + 1));
+      case kMode_Operand2_R_UXTB:
+        return Operand(InputRegister32(index), UXTB);
+      case kMode_Operand2_R_UXTH:
+        return Operand(InputRegister32(index), UXTH);
       case kMode_MRI:
       case kMode_MRR:
         break;
@@ -91,6 +95,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
         return Operand(InputRegister64(index), ASR, InputInt6(index + 1));
       case kMode_Operand2_R_ROR_I:
         return Operand(InputRegister64(index), ROR, InputInt6(index + 1));
+      case kMode_Operand2_R_UXTB:
+        return Operand(InputRegister64(index), UXTB);
+      case kMode_Operand2_R_UXTH:
+        return Operand(InputRegister64(index), UXTH);
       case kMode_MRI:
       case kMode_MRR:
         break;
@@ -107,6 +115,8 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
       case kMode_Operand2_R_LSR_I:
       case kMode_Operand2_R_ASR_I:
       case kMode_Operand2_R_ROR_I:
+      case kMode_Operand2_R_UXTB:
+      case kMode_Operand2_R_UXTH:
         break;
       case kMode_MRI:
         *first_index += 2;
index 242d25d..dfd90da 100644 (file)
@@ -130,13 +130,15 @@ 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 */
+#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) */
 
 }  // namespace internal
 }  // namespace compiler
index fedda24..edef438 100644 (file)
@@ -167,6 +167,25 @@ static bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
 }
 
 
+static bool TryMatchAnyExtend(InstructionSelector* selector, Node* node,
+                              InstructionCode* opcode) {
+  NodeMatcher nm(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);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
 // Shared routine for multiple binary operations.
 template <typename Matcher>
 static void VisitBinop(InstructionSelector* selector, Node* node,
@@ -178,28 +197,38 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
   size_t input_count = 0;
   InstructionOperand outputs[2];
   size_t output_count = 0;
-  bool try_ror_operand = true;
+  bool is_add_sub = false;
 
   if (m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || m.IsInt64Sub()) {
-    try_ror_operand = false;
+    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,
-                              try_ror_operand)) {
+                              !is_add_sub)) {
     Matcher m_shift(m.right().node());
     inputs[input_count++] = g.UseRegister(m.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,
-                              try_ror_operand)) {
+                              !is_add_sub)) {
     Matcher m_shift(m.left().node());
     inputs[input_count++] = g.UseRegister(m.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());
index aea6262..163175b 100644 (file)
@@ -472,6 +472,36 @@ TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
 }
 
 
+TEST_P(InstructionSelectorAddSubTest, ExtendByte) {
+  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.Word32And(m.Parameter(1), m.Int32Constant(0xff))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) {
+  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.Word32And(m.Parameter(1), m.Int32Constant(0xffff))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R_UXTH, 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));
 
@@ -616,6 +646,58 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
 }
 
 
+TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTB, 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.Word32And(m.Parameter(0), m.Int32Constant(0xff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTH, 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.Word32And(m.Parameter(0), m.Int32Constant(0xffff)),
+                        m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Data processing controlled branches.