} 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)
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());
}
}
- // 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();
}
}
+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.