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

Side by Side Diff: test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc

Issue 2087233005: [arm64] Fix handling of CMN and ADD/SUB with overflow in VisitBinop. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 6 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 unified diff | Download patch
« no previous file with comments | « src/compiler/arm64/instruction-selector-arm64.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "test/unittests/compiler/instruction-selector-unittest.h" 5 #include "test/unittests/compiler/instruction-selector-unittest.h"
6 6
7 namespace v8 { 7 namespace v8 {
8 namespace internal { 8 namespace internal {
9 namespace compiler { 9 namespace compiler {
10 10
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 MachineType::Int32()}, 177 MachineType::Int32()},
178 {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst, 178 {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst,
179 MachineType::Int64()}}; 179 MachineType::Int64()}};
180 180
181 181
182 // ARM64 arithmetic with overflow instructions. 182 // ARM64 arithmetic with overflow instructions.
183 const MachInst2 kOvfAddSubInstructions[] = { 183 const MachInst2 kOvfAddSubInstructions[] = {
184 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow", 184 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
185 kArm64Add32, MachineType::Int32()}, 185 kArm64Add32, MachineType::Int32()},
186 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow", 186 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
187 kArm64Sub32, MachineType::Int32()}}; 187 kArm64Sub32, MachineType::Int32()},
188 188 {&RawMachineAssembler::Int64AddWithOverflow, "Int64AddWithOverflow",
189 kArm64Add, MachineType::Int64()},
190 {&RawMachineAssembler::Int64SubWithOverflow, "Int64SubWithOverflow",
191 kArm64Sub, MachineType::Int64()}};
189 192
190 // ARM64 shift instructions. 193 // ARM64 shift instructions.
191 const Shift kShiftInstructions[] = { 194 const Shift kShiftInstructions[] = {
192 {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, 195 {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32,
193 MachineType::Int32()}, 196 MachineType::Int32()},
194 kMode_Operand2_R_LSL_I}, 197 kMode_Operand2_R_LSL_I},
195 {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, 198 {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl,
196 MachineType::Int64()}, 199 MachineType::Int64()},
197 kMode_Operand2_R_LSL_I}, 200 kMode_Operand2_R_LSL_I},
198 {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, 201 {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32,
(...skipping 1400 matching lines...) Expand 10 before | Expand all | Expand 10 after
1599 Stream s = m.Build(); 1602 Stream s = m.Build();
1600 ASSERT_EQ(1U, s.size()); 1603 ASSERT_EQ(1U, s.size());
1601 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1604 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1602 ASSERT_EQ(4U, s[0]->InputCount()); 1605 ASSERT_EQ(4U, s[0]->InputCount());
1603 EXPECT_EQ(1U, s[0]->OutputCount()); 1606 EXPECT_EQ(1U, s[0]->OutputCount());
1604 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1607 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1605 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1608 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1606 } 1609 }
1607 } 1610 }
1608 1611
1612 TEST_P(InstructionSelectorOvfAddSubTest, RORShift) {
1613 // ADD and SUB do not support ROR shifts, make sure we do not try
1614 // to merge them into the ADD/SUB instruction.
1615 const MachInst2 dpi = GetParam();
1616 const MachineType type = dpi.machine_type;
1617 auto rotate = &RawMachineAssembler::Word64Ror;
1618 ArchOpcode rotate_opcode = kArm64Ror;
1619 if (type == MachineType::Int32()) {
1620 rotate = &RawMachineAssembler::Word32Ror;
1621 rotate_opcode = kArm64Ror32;
1622 }
1623 TRACED_FORRANGE(int32_t, imm, -32, 63) {
1624 StreamBuilder m(this, type, type, type);
1625 Node* const p0 = m.Parameter(0);
1626 Node* const p1 = m.Parameter(1);
1627 Node* r = (m.*rotate)(p1, m.Int32Constant(imm));
1628 m.Return((m.*dpi.constructor)(p0, r));
1629 Stream s = m.Build();
1630 ASSERT_EQ(2U, s.size());
1631 EXPECT_EQ(rotate_opcode, s[0]->arch_opcode());
1632 EXPECT_EQ(dpi.arch_opcode, s[1]->arch_opcode());
1633 }
1634 }
1609 1635
1610 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 1636 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1611 InstructionSelectorOvfAddSubTest, 1637 InstructionSelectorOvfAddSubTest,
1612 ::testing::ValuesIn(kOvfAddSubInstructions)); 1638 ::testing::ValuesIn(kOvfAddSubInstructions));
1613 1639
1614 1640
1615 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) { 1641 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
1616 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1642 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1617 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1643 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1618 m.Return(m.Projection( 1644 m.Return(m.Projection(
(...skipping 1373 matching lines...) Expand 10 before | Expand all | Expand 10 after
2992 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3018 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
2993 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 3019 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
2994 } 3020 }
2995 } 3021 }
2996 3022
2997 namespace { 3023 namespace {
2998 3024
2999 struct IntegerCmp { 3025 struct IntegerCmp {
3000 MachInst2 mi; 3026 MachInst2 mi;
3001 FlagsCondition cond; 3027 FlagsCondition cond;
3028 FlagsCondition commuted_cond;
3002 }; 3029 };
3003 3030
3004 3031
3005 std::ostream& operator<<(std::ostream& os, const IntegerCmp& cmp) { 3032 std::ostream& operator<<(std::ostream& os, const IntegerCmp& cmp) {
3006 return os << cmp.mi; 3033 return os << cmp.mi;
3007 } 3034 }
3008 3035
3009 3036
3010 // ARM64 32-bit integer comparison instructions. 3037 // ARM64 32-bit integer comparison instructions.
3011 const IntegerCmp kIntegerCmpInstructions[] = { 3038 const IntegerCmp kIntegerCmpInstructions[] = {
3012 {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, 3039 {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
3013 MachineType::Int32()}, 3040 MachineType::Int32()},
3041 kEqual,
3014 kEqual}, 3042 kEqual},
3015 {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32, 3043 {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32,
3016 MachineType::Int32()}, 3044 MachineType::Int32()},
3017 kSignedLessThan}, 3045 kSignedLessThan,
3046 kSignedGreaterThan},
3018 {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual", 3047 {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
3019 kArm64Cmp32, MachineType::Int32()}, 3048 kArm64Cmp32, MachineType::Int32()},
3020 kSignedLessThanOrEqual}, 3049 kSignedLessThanOrEqual,
3050 kSignedGreaterThanOrEqual},
3021 {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32, 3051 {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32,
3022 MachineType::Uint32()}, 3052 MachineType::Uint32()},
3023 kUnsignedLessThan}, 3053 kUnsignedLessThan,
3054 kUnsignedGreaterThan},
3024 {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual", 3055 {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
3025 kArm64Cmp32, MachineType::Uint32()}, 3056 kArm64Cmp32, MachineType::Uint32()},
3026 kUnsignedLessThanOrEqual}}; 3057 kUnsignedLessThanOrEqual,
3058 kUnsignedGreaterThanOrEqual}};
3027 3059
3028 } // namespace 3060 } // namespace
3029 3061
3030 3062
3031 TEST_F(InstructionSelectorTest, Word32CompareNegateWithWord32Shift) { 3063 TEST_F(InstructionSelectorTest, Word32CompareNegateWithWord32Shift) {
3032 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3064 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3033 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 3065 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
3034 // Test 32-bit operations. Ignore ROR shifts, as compare-negate does not 3066 // Test 32-bit operations. Ignore ROR shifts, as compare-negate does not
3035 // support them. 3067 // support them.
3036 if (shift.mi.machine_type != MachineType::Int32() || 3068 if (shift.mi.machine_type != MachineType::Int32() ||
(...skipping 16 matching lines...) Expand all
3053 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 3085 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
3054 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); 3086 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
3055 EXPECT_EQ(1U, s[0]->OutputCount()); 3087 EXPECT_EQ(1U, s[0]->OutputCount());
3056 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3088 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3057 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 3089 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3058 } 3090 }
3059 } 3091 }
3060 } 3092 }
3061 } 3093 }
3062 3094
3095 TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) {
3096 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3097 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
3098 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which
3099 // is tested elsewhere.
3100 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue;
3101 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
3102 Node* const p0 = m.Parameter(0);
3103 RawMachineLabel a, b;
3104 m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0), &a, &b);
3105 m.Bind(&a);
3106 m.Return(m.Int32Constant(1));
3107 m.Bind(&b);
3108 m.Return(m.Int32Constant(0));
3109 Stream s = m.Build();
3110 ASSERT_EQ(1U, s.size());
3111 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3112 ASSERT_LE(2U, s[0]->InputCount());
3113 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
3114 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
3115 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
3116 }
3117 }
3118 }
3119
3120 TEST_F(InstructionSelectorTest, CmnWithImmediateOnLeft) {
3121 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3122 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
3123 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which
3124 // is tested elsewhere.
3125 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue;
3126 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
3127 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0));
3128 RawMachineLabel a, b;
3129 m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub), &a, &b);
3130 m.Bind(&a);
3131 m.Return(m.Int32Constant(1));
3132 m.Bind(&b);
3133 m.Return(m.Int32Constant(0));
3134 Stream s = m.Build();
3135 ASSERT_EQ(1U, s.size());
3136 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
3137 ASSERT_LE(2U, s[0]->InputCount());
3138 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
3139 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3140 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
3141 }
3142 }
3143 }
3144
3145 TEST_F(InstructionSelectorTest, CmpSignedExtendByteOnLeft) {
3146 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3147 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3148 MachineType::Int32());
3149 Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
3150 m.Int32Constant(24));
3151 m.Return((m.*cmp.mi.constructor)(extend, m.Parameter(1)));
3152 Stream s = m.Build();
3153 ASSERT_EQ(1U, s.size());
3154 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3155 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3156 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
3157 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
3158 }
3159 }
3160
3161 TEST_F(InstructionSelectorTest, CmnSignedExtendByteOnLeft) {
3162 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3163 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3164 MachineType::Int32());
3165 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0));
3166 Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
3167 m.Int32Constant(24));
3168 m.Return((m.*cmp.mi.constructor)(extend, sub));
3169 Stream s = m.Build();
3170 ASSERT_EQ(1U, s.size());
3171 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
3172 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3173 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3174 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
3175 }
3176 }
3177
3178 TEST_F(InstructionSelectorTest, CmpShiftByImmediateOnLeft) {
3179 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3180 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
3181 // Only test relevant shifted operands.
3182 if (shift.mi.machine_type != MachineType::Int32()) continue;
3183
3184 // The available shift operand range is `0 <= imm < 32`, but we also test
3185 // that immediates outside this range are handled properly (modulo-32).
3186 TRACED_FORRANGE(int, imm, -32, 63) {
3187 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3188 MachineType::Int32());
3189 m.Return((m.*cmp.mi.constructor)(
3190 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
3191 m.Parameter(0)));
3192 Stream s = m.Build();
3193 // Cmp does not support ROR shifts.
3194 if (shift.mi.arch_opcode == kArm64Ror32) {
3195 ASSERT_EQ(2U, s.size());
3196 continue;
3197 }
3198 ASSERT_EQ(1U, s.size());
3199 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3200 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
3201 EXPECT_EQ(3U, s[0]->InputCount());
3202 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
3203 EXPECT_EQ(1U, s[0]->OutputCount());
3204 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3205 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
3206 }
3207 }
3208 }
3209 }
3210
3211 TEST_F(InstructionSelectorTest, CmnShiftByImmediateOnLeft) {
3212 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3213 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
3214 // Only test relevant shifted operands.
3215 if (shift.mi.machine_type != MachineType::Int32()) continue;
3216
3217 // The available shift operand range is `0 <= imm < 32`, but we also test
3218 // that immediates outside this range are handled properly (modulo-32).
3219 TRACED_FORRANGE(int, imm, -32, 63) {
3220 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3221 MachineType::Int32());
3222 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0));
3223 m.Return((m.*cmp.mi.constructor)(
3224 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
3225 sub));
3226 Stream s = m.Build();
3227 // Cmn does not support ROR shifts.
3228 if (shift.mi.arch_opcode == kArm64Ror32) {
3229 ASSERT_EQ(2U, s.size());
3230 continue;
3231 }
3232 ASSERT_EQ(1U, s.size());
3233 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
3234 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
3235 EXPECT_EQ(3U, s[0]->InputCount());
3236 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
3237 EXPECT_EQ(1U, s[0]->OutputCount());
3238 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3239 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3240 }
3241 }
3242 }
3243 }
3244
3063 3245
3064 // ----------------------------------------------------------------------------- 3246 // -----------------------------------------------------------------------------
3065 // Miscellaneous 3247 // Miscellaneous
3066 3248
3067 3249
3068 static const MachInst2 kLogicalWithNotRHSs[] = { 3250 static const MachInst2 kLogicalWithNotRHSs[] = {
3069 {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, 3251 {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32,
3070 MachineType::Int32()}, 3252 MachineType::Int32()},
3071 {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, 3253 {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic,
3072 MachineType::Int64()}, 3254 MachineType::Int64()},
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after
3753 EXPECT_EQ(kArm64Float64Neg, s[0]->arch_opcode()); 3935 EXPECT_EQ(kArm64Float64Neg, s[0]->arch_opcode());
3754 ASSERT_EQ(1U, s[0]->InputCount()); 3936 ASSERT_EQ(1U, s[0]->InputCount());
3755 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3937 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3756 ASSERT_EQ(1U, s[0]->OutputCount()); 3938 ASSERT_EQ(1U, s[0]->OutputCount());
3757 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3939 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
3758 } 3940 }
3759 3941
3760 } // namespace compiler 3942 } // namespace compiler
3761 } // namespace internal 3943 } // namespace internal
3762 } // namespace v8 3944 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/arm64/instruction-selector-arm64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698