From ad815be7d59f11c0cd7b9a76346a399cf0d71769 Mon Sep 17 00:00:00 2001 From: "baptiste.afsa@arm.com" Date: Wed, 12 Nov 2014 10:06:12 +0000 Subject: [PATCH] [turbofan] Use cbz/cbnz when possible on arm64. 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 | 30 ++++++++++++------- src/compiler/arm64/instruction-codes-arm64.h | 2 ++ src/compiler/arm64/instruction-selector-arm64.cc | 7 +++-- .../arm64/instruction-selector-arm64-unittest.cc | 35 ++++++++++++++++++++++ 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index 41d4c54..f48a723 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc @@ -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()); diff --git a/src/compiler/arm64/instruction-codes-arm64.h b/src/compiler/arm64/instruction-codes-arm64.h index f7af844..a529ebf 100644 --- a/src/compiler/arm64/instruction-codes-arm64.h +++ b/src/compiler/arm64/instruction-codes-arm64.h @@ -72,6 +72,8 @@ namespace compiler { V(Arm64Tbz32) \ V(Arm64Tbnz) \ V(Arm64Tbnz32) \ + V(Arm64Cbz32) \ + V(Arm64Cbnz32) \ V(Arm64Claim) \ V(Arm64Poke) \ V(Arm64PokePairZero) \ diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index 151d1aa..aba7eb0 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc @@ -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(); } diff --git a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc index eee9c58..2d127c4 100644 --- a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -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. -- 2.7.4