Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Unified Diff: test/unittests/compiler/arm/instruction-selector-arm-unittest.cc

Issue 2152253002: [ARM] Generate flag setting instructions for arm. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/arm/instruction-selector-arm.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
diff --git a/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
index fa030394d761e6c3c1c2210feddb97855986fdd7..56cdbbdb38afe1336793f2aa02effe797fd7eec9 100644
--- a/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
+++ b/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
@@ -2004,6 +2004,250 @@ TEST_F(InstructionSelectorTest, Float64Sqrt) {
EXPECT_EQ(kFlags_none, s[0]->flags_mode());
}
+// -----------------------------------------------------------------------------
+// Flag-setting instructions.
+
+const Comparison kBinopCmpZeroRightInstructions[] = {
+ {&RawMachineAssembler::Word32Equal, "Word32Equal", kEqual, kNotEqual,
+ kEqual},
+ {&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kNotEqual, kEqual,
+ kNotEqual},
+ {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kNegative,
+ kPositiveOrZero, kNegative},
+ {&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
+ kPositiveOrZero, kNegative, kPositiveOrZero},
+ {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+ kEqual, kNotEqual, kEqual},
+ {&RawMachineAssembler::Uint32GreaterThan, "Uint32GreaterThan", kNotEqual,
+ kEqual, kNotEqual}};
+
+const Comparison kBinopCmpZeroLeftInstructions[] = {
+ {&RawMachineAssembler::Word32Equal, "Word32Equal", kEqual, kNotEqual,
+ kEqual},
+ {&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kNotEqual, kEqual,
+ kNotEqual},
+ {&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kNegative,
+ kPositiveOrZero, kNegative},
+ {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+ kPositiveOrZero, kNegative, kPositiveOrZero},
+ {&RawMachineAssembler::Uint32GreaterThanOrEqual, "Uint32GreaterThanOrEqual",
+ kEqual, kNotEqual, kEqual},
+ {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kNotEqual, kEqual,
+ kNotEqual}};
+
+struct FlagSettingInst {
+ Constructor constructor;
+ const char* constructor_name;
+ ArchOpcode arch_opcode;
+ ArchOpcode no_output_opcode;
+};
+
+std::ostream& operator<<(std::ostream& os, const FlagSettingInst& inst) {
+ return os << inst.constructor_name;
+}
+
+const FlagSettingInst kFlagSettingInstructions[] = {
+ {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmCmn},
+ {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmTst},
+ {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr},
+ {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmTeq}};
+
+typedef InstructionSelectorTestWithParam<FlagSettingInst>
+ InstructionSelectorFlagSettingTest;
+
+TEST_P(InstructionSelectorFlagSettingTest, CmpZeroRight) {
+ const FlagSettingInst inst = GetParam();
+ // Binop with single user : a cmp instruction.
+ TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) {
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
+ MachineType::Int32());
+ RawMachineLabel a, b;
+ Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1));
+ Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0));
+ m.Branch(comp, &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());
+ ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs.
+ EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
+ EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+ }
+}
+
+TEST_P(InstructionSelectorFlagSettingTest, CmpZeroLeft) {
+ const FlagSettingInst inst = GetParam();
+ // Test a cmp with zero on the left-hand side.
+ TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroLeftInstructions) {
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
+ MachineType::Int32());
+ RawMachineLabel a, b;
+ Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1));
+ Node* comp = (m.*cmp.constructor)(m.Int32Constant(0), binop);
+ m.Branch(comp, &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());
+ ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs.
+ EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
+ EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+ }
+}
+
+TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) {
+ const FlagSettingInst inst = GetParam();
+ // Binop with additional users, but in a different basic block.
+ TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) {
+ // We don't optimise this case at the moment.
+ if (cmp.flags_condition == kEqual || cmp.flags_condition == kNotEqual) {
+ continue;
+ }
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
+ MachineType::Int32());
+ RawMachineLabel a, b;
+ Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1));
+ Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0));
+ m.Branch(comp, &a, &b);
+ m.Bind(&a);
+ m.Return(binop);
+ m.Bind(&b);
+ m.Return(m.Int32Constant(0));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs.
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
+ EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+ }
+}
+
+TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) {
+ const FlagSettingInst inst = GetParam();
+ // Like the test above, but with a shifted input to the binary operator.
+ TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) {
+ // We don't optimise this case at the moment.
+ if (cmp.flags_condition == kEqual || cmp.flags_condition == kNotEqual) {
+ continue;
+ }
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
+ MachineType::Int32());
+ RawMachineLabel a, b;
+ Node* imm = m.Int32Constant(5);
+ Node* shift = m.Word32Shl(m.Parameter(1), imm);
+ Node* binop = (m.*inst.constructor)(m.Parameter(0), shift);
+ Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0));
+ m.Branch(comp, &a, &b);
+ m.Bind(&a);
+ m.Return(binop);
+ m.Bind(&b);
+ m.Return(m.Int32Constant(0));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ ASSERT_EQ(5U, s[0]->InputCount()); // The labels are also inputs.
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
+ EXPECT_EQ(5, s.ToInt32(s[0]->InputAt(2)));
+ EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+ EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+ }
+}
+
+TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) {
+ const FlagSettingInst inst = GetParam();
+ // Binop with additional users, in the same basic block. We need to make sure
+ // we don't try to optimise this case.
+ TRACED_FOREACH(Comparison, cmp, kComparisons) {
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
+ MachineType::Int32());
+ RawMachineLabel a, b;
+ Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1));
+ Node* mul = m.Int32Mul(m.Parameter(0), binop);
+ Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0));
+ m.Branch(comp, &a, &b);
+ m.Bind(&a);
+ m.Return(mul);
+ m.Bind(&b);
+ m.Return(m.Int32Constant(0));
+ Stream s = m.Build();
+ ASSERT_EQ(3U, s.size());
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_NE(kFlags_branch, s[0]->flags_mode());
+ EXPECT_EQ(kArmMul, s[1]->arch_opcode());
+ EXPECT_EQ(cmp.flags_condition == kEqual ? kArmTst : kArmCmp,
+ s[2]->arch_opcode());
+ EXPECT_EQ(kFlags_branch, s[2]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[2]->flags_condition());
+ }
+}
+
+TEST_P(InstructionSelectorFlagSettingTest, CommuteImmediate) {
+ const FlagSettingInst inst = GetParam();
+ // Immediate on left hand side of the binary operator.
+ TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) {
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
+ RawMachineLabel a, b;
+ Node* imm = m.Int32Constant(3);
+ Node* binop = (m.*inst.constructor)(imm, m.Parameter(0));
+ Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0));
+ m.Branch(comp, &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());
+ ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs.
+ EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(3, s.ToInt32(s[0]->InputAt(1)));
+ EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+ }
+}
+
+TEST_P(InstructionSelectorFlagSettingTest, CommuteShift) {
+ const FlagSettingInst inst = GetParam();
+ // Left-hand side operand shifted by immediate.
+ TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) {
+ TRACED_FOREACH(Shift, shift, kShifts) {
+ StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
+ MachineType::Int32());
+ Node* imm = m.Int32Constant(5);
+ Node* shifted_operand = (m.*shift.constructor)(m.Parameter(0), imm);
+ Node* binop = (m.*inst.constructor)(shifted_operand, m.Parameter(1));
+ Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0));
+ m.Return(comp);
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+ EXPECT_EQ(3U, s[0]->InputCount());
+ EXPECT_EQ(5, s.ToInt64(s[0]->InputAt(2)));
+ EXPECT_EQ(inst.arch_opcode == kArmOrr ? 2U : 1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+ InstructionSelectorFlagSettingTest,
+ ::testing::ValuesIn(kFlagSettingInstructions));
// -----------------------------------------------------------------------------
// Miscellaneous.
« no previous file with comments | « src/compiler/arm/instruction-selector-arm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698