[turbofan] Use cbz/cbnz when possible on arm64.
authorbaptiste.afsa@arm.com <baptiste.afsa@arm.com>
Wed, 12 Nov 2014 10:06:12 +0000 (10:06 +0000)
committerbaptiste.afsa@arm.com <baptiste.afsa@arm.com>
Wed, 12 Nov 2014 10:06:46 +0000 (10:06 +0000)
R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25288}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25288 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

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 41d4c5458d2bcb0c622e51ae931d9c5ddd8c92bc..f48a7239e0f8085de3a5b39bddc204e11d2395a0 100644 (file)
@@ -172,12 +172,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
   } while (0)
 
 
-#define ASSEMBLE_TEST_AND_BRANCH(asm_instr, width)           \
-  do {                                                       \
-    bool fallthrough = IsNextInAssemblyOrder(i.InputRpo(3)); \
-    __ asm_instr(i.InputRegister##width(0), i.InputInt6(1),  \
-                 GetLabel(i.InputRpo(2)));                   \
-    if (!fallthrough) __ B(GetLabel(i.InputRpo(3)));         \
+#define ASSEMBLE_BRANCH_TO(target)                    \
+  do {                                                \
+    bool fallthrough = IsNextInAssemblyOrder(target); \
+    if (!fallthrough) __ B(GetLabel(target));         \
   } while (0)
 
 
@@ -430,16 +428,28 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
               i.InputInt8(2));
       break;
     case kArm64Tbz:
-      ASSEMBLE_TEST_AND_BRANCH(Tbz, 64);
+      __ Tbz(i.InputRegister64(0), i.InputInt6(1), GetLabel(i.InputRpo(2)));
+      ASSEMBLE_BRANCH_TO(i.InputRpo(3));
       break;
     case kArm64Tbz32:
-      ASSEMBLE_TEST_AND_BRANCH(Tbz, 32);
+      __ Tbz(i.InputRegister32(0), i.InputInt5(1), GetLabel(i.InputRpo(2)));
+      ASSEMBLE_BRANCH_TO(i.InputRpo(3));
       break;
     case kArm64Tbnz:
-      ASSEMBLE_TEST_AND_BRANCH(Tbnz, 64);
+      __ Tbnz(i.InputRegister64(0), i.InputInt6(1), GetLabel(i.InputRpo(2)));
+      ASSEMBLE_BRANCH_TO(i.InputRpo(3));
       break;
     case kArm64Tbnz32:
-      ASSEMBLE_TEST_AND_BRANCH(Tbnz, 32);
+      __ Tbnz(i.InputRegister32(0), i.InputInt5(1), GetLabel(i.InputRpo(2)));
+      ASSEMBLE_BRANCH_TO(i.InputRpo(3));
+      break;
+    case kArm64Cbz32:
+      __ Cbz(i.InputRegister32(0), GetLabel(i.InputRpo(1)));
+      ASSEMBLE_BRANCH_TO(i.InputRpo(2));
+      break;
+    case kArm64Cbnz32:
+      __ Cbnz(i.InputRegister32(0), GetLabel(i.InputRpo(1)));
+      ASSEMBLE_BRANCH_TO(i.InputRpo(2));
       break;
     case kArm64Claim: {
       int words = MiscField::decode(instr->opcode());
index f7af844267ade0a6f35f48d71d91dca333889eb2..a529ebfd69d5712474cbfd3414d5d92074a10fe7 100644 (file)
@@ -72,6 +72,8 @@ namespace compiler {
   V(Arm64Tbz32)                    \
   V(Arm64Tbnz)                     \
   V(Arm64Tbnz32)                   \
+  V(Arm64Cbz32)                    \
+  V(Arm64Cbnz32)                   \
   V(Arm64Claim)                    \
   V(Arm64Poke)                     \
   V(Arm64PokePairZero)             \
index 151d1aa8b7eac05d1612c657a833c2e0695d0133..aba7eb0189e1bb960624f8f7a4e2ba47a505b222 100644 (file)
@@ -1270,8 +1270,11 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
     }
   }
 
-  // Branch could not be combined with a compare, emit compare against 0.
-  VisitWord32Test(this, value, &cont);
+  // Branch could not be combined with a compare, compare against 0 and branch.
+  DCHECK((cont.condition() == kEqual) || (cont.condition() == kNotEqual));
+  ArchOpcode opcode = (cont.condition() == kEqual) ? kArm64Cbz32 : kArm64Cbnz32;
+  Emit(opcode, NULL, g.UseRegister(value), g.Label(cont.true_block()),
+       g.Label(cont.false_block()))->MarkAsControl();
 }
 
 
index eee9c58b127ddac04e6439708f3af73c6d0c910d..2d127c448fbf223ce6eca98f3ee8be25e31d2438 100644 (file)
@@ -952,6 +952,41 @@ TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
 }
 
 
+TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* p0 = m.Parameter(0);
+    m.Branch(p0, &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cbnz32, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  }
+
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* p0 = m.Parameter(0);
+    m.Branch(m.Word32BinaryNot(p0), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cbz32, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Add and subtract instructions with overflow.