[turbofan] Use sbfx in ARM64 instruction selector
authormartyn.capewell <martyn.capewell@arm.com>
Fri, 8 May 2015 12:51:42 +0000 (05:51 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 8 May 2015 12:51:43 +0000 (12:51 +0000)
Select sbfx for ((x << k) >> k) in ARM64 instruction selector, and similarly
for ubfx. This is a more generic version of the previous sxtb/h selector.

BUG=

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

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

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 dc045af64b4775f6765e1f13644ecf8167e8da8c..01de1b0735c51a904da05aa06a52866f3227573c 100644 (file)
@@ -642,13 +642,17 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Sxtw:
       __ Sxtw(i.OutputRegister(), i.InputRegister32(0));
       break;
+    case kArm64Sbfx32:
+      __ Sbfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt5(1),
+              i.InputInt5(2));
+      break;
     case kArm64Ubfx:
-      __ Ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
-              i.InputInt8(2));
+      __ Ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt6(1),
+              i.InputInt6(2));
       break;
     case kArm64Ubfx32:
-      __ Ubfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt8(1),
-              i.InputInt8(2));
+      __ Ubfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt5(1),
+              i.InputInt5(2));
       break;
     case kArm64Bfi:
       __ Bfi(i.OutputRegister(), i.InputRegister(1), i.InputInt6(2),
index 3a6037bc5dafdbfc269d983b0ce2c86318f8ba79..d888c0b1c3d6a9748834de5bbbaecf5422000c16 100644 (file)
@@ -69,6 +69,7 @@ namespace compiler {
   V(Arm64Sxtb32)                   \
   V(Arm64Sxth32)                   \
   V(Arm64Sxtw)                     \
+  V(Arm64Sbfx32)                   \
   V(Arm64Ubfx)                     \
   V(Arm64Ubfx32)                   \
   V(Arm64Bfi)                      \
index 52bd9790c0b2a3a4bc201177b30c0990b5389071..26e9b8cad9010594ca22b5308bad624acdf67c35 100644 (file)
@@ -660,8 +660,36 @@ void InstructionSelector::VisitWord64Shl(Node* node) {
 }
 
 
+namespace {
+
+bool TryEmitBitfieldExtract32(InstructionSelector* selector, Node* node) {
+  Arm64OperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  if (selector->CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
+    // Select Ubfx or Sbfx for (x << (K & 0x1f)) OP (K & 0x1f), where
+    // OP is >>> or >> and (K & 0x1f) != 0.
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().HasValue() && m.right().HasValue() &&
+        (mleft.right().Value() & 0x1f) == (m.right().Value() & 0x1f)) {
+      DCHECK(m.IsWord32Shr() || m.IsWord32Sar());
+      ArchOpcode opcode = m.IsWord32Sar() ? kArm64Sbfx32 : kArm64Ubfx32;
+
+      int right_val = m.right().Value() & 0x1f;
+      DCHECK_NE(right_val, 0);
+
+      selector->Emit(opcode, g.DefineAsRegister(node),
+                     g.UseRegister(mleft.left().node()), g.TempImmediate(0),
+                     g.TempImmediate(32 - right_val));
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+
 void InstructionSelector::VisitWord32Shr(Node* node) {
-  Arm64OperandGenerator g(this);
   Int32BinopMatcher m(node);
   if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) {
     uint32_t lsb = m.right().Value();
@@ -673,6 +701,7 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
       // Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
       // shifted into the least-significant bits.
       if ((mask_msb + mask_width + lsb) == 32) {
+        Arm64OperandGenerator g(this);
         DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(mask));
         Emit(kArm64Ubfx32, g.DefineAsRegister(node),
              g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
@@ -680,6 +709,8 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
         return;
       }
     }
+  } else if (TryEmitBitfieldExtract32(this, node)) {
+    return;
   }
   VisitRRO(this, kArm64Lsr32, node, kShift32Imm);
 }
@@ -711,20 +742,8 @@ void InstructionSelector::VisitWord64Shr(Node* node) {
 
 
 void InstructionSelector::VisitWord32Sar(Node* node) {
-  Arm64OperandGenerator g(this);
-  Int32BinopMatcher m(node);
-  // Select Sxth/Sxtb for (x << K) >> K where K is 16 or 24.
-  if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
-    Int32BinopMatcher mleft(m.left().node());
-    if (mleft.right().Is(16) && m.right().Is(16)) {
-      Emit(kArm64Sxth32, g.DefineAsRegister(node),
-           g.UseRegister(mleft.left().node()));
-      return;
-    } else if (mleft.right().Is(24) && m.right().Is(24)) {
-      Emit(kArm64Sxtb32, g.DefineAsRegister(node),
-           g.UseRegister(mleft.left().node()));
-      return;
-    }
+  if (TryEmitBitfieldExtract32(this, node)) {
+    return;
   }
   VisitRRO(this, kArm64Asr32, node, kShift32Imm);
 }
index cd825e239ba421a84678182a10b67d724bb3a1ce..744f18f0bdb0bd7e4c133016d50f6f939417baeb 100644 (file)
@@ -2366,30 +2366,62 @@ TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
 
 
 TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
-  {
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
     StreamBuilder m(this, kMachInt32, kMachInt32);
     Node* const p0 = m.Parameter(0);
-    Node* const r =
-        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
+    Node* const r = m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(shift)),
+                                m.Int32Constant(shift));
     m.Return(r);
     Stream s = m.Build();
     ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Sxtb32, s[0]->arch_opcode());
-    ASSERT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(kArm64Sbfx32, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
     ASSERT_EQ(1U, s[0]->OutputCount());
     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
   }
-  {
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
     StreamBuilder m(this, kMachInt32, kMachInt32);
     Node* const p0 = m.Parameter(0);
-    Node* const r =
-        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
+    Node* const r = m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(shift + 32)),
+                                m.Int32Constant(shift + 64));
     m.Return(r);
     Stream s = m.Build();
     ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Sxth32, s[0]->arch_opcode());
-    ASSERT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(kArm64Sbfx32, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32ShrWithWord32Shl) {
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r = m.Word32Shr(m.Word32Shl(p0, m.Int32Constant(shift)),
+                                m.Int32Constant(shift));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r = m.Word32Shr(m.Word32Shl(p0, m.Int32Constant(shift + 32)),
+                                m.Int32Constant(shift + 64));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
     ASSERT_EQ(1U, s[0]->OutputCount());
     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));