| OLD | NEW |
| 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 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| 11 namespace compiler { | 11 namespace compiler { |
| 12 | 12 |
| 13 namespace { | |
| 14 | |
| 15 // Immediates (random subset). | |
| 16 static const int32_t kImmediates[] = { | |
| 17 kMinInt, -42, -1, 0, 1, 2, 3, 4, 5, | |
| 18 6, 7, 8, 16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt}; | |
| 19 | |
| 20 } // namespace | |
| 21 | |
| 22 | |
| 23 // ----------------------------------------------------------------------------- | 13 // ----------------------------------------------------------------------------- |
| 24 // Conversions. | 14 // Conversions. |
| 25 | 15 |
| 26 | 16 |
| 27 TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) { | 17 TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) { |
| 28 StreamBuilder m(this, kMachFloat32, kMachFloat64); | 18 StreamBuilder m(this, kMachFloat32, kMachFloat64); |
| 29 m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0))); | 19 m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0))); |
| 30 Stream s = m.Build(); | 20 Stream s = m.Build(); |
| 31 ASSERT_EQ(1U, s.size()); | 21 ASSERT_EQ(1U, s.size()); |
| 32 EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode()); | 22 EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) { | 66 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) { |
| 77 StreamBuilder m(this, kMachInt32, kMachInt64); | 67 StreamBuilder m(this, kMachInt32, kMachInt64); |
| 78 m.Return(m.TruncateInt64ToInt32(m.Parameter(0))); | 68 m.Return(m.TruncateInt64ToInt32(m.Parameter(0))); |
| 79 Stream s = m.Build(); | 69 Stream s = m.Build(); |
| 80 ASSERT_EQ(1U, s.size()); | 70 ASSERT_EQ(1U, s.size()); |
| 81 EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); | 71 EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); |
| 82 } | 72 } |
| 83 | 73 |
| 84 | 74 |
| 85 // ----------------------------------------------------------------------------- | 75 // ----------------------------------------------------------------------------- |
| 86 // Better left operand for commutative binops | |
| 87 | |
| 88 TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) { | |
| 89 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | |
| 90 Node* param1 = m.Parameter(0); | |
| 91 Node* param2 = m.Parameter(1); | |
| 92 Node* add = m.Int32Add(param1, param2); | |
| 93 m.Return(m.Int32Add(add, param1)); | |
| 94 Stream s = m.Build(); | |
| 95 ASSERT_EQ(2U, s.size()); | |
| 96 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); | |
| 97 ASSERT_EQ(2U, s[0]->InputCount()); | |
| 98 ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated()); | |
| 99 EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(0))); | |
| 100 } | |
| 101 | |
| 102 | |
| 103 TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) { | |
| 104 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | |
| 105 Node* param1 = m.Parameter(0); | |
| 106 Node* param2 = m.Parameter(1); | |
| 107 Node* mul = m.Int32Mul(param1, param2); | |
| 108 m.Return(m.Int32Mul(mul, param1)); | |
| 109 Stream s = m.Build(); | |
| 110 ASSERT_EQ(2U, s.size()); | |
| 111 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); | |
| 112 ASSERT_EQ(2U, s[0]->InputCount()); | |
| 113 ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated()); | |
| 114 EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(0))); | |
| 115 } | |
| 116 | |
| 117 | |
| 118 // ----------------------------------------------------------------------------- | |
| 119 // Loads and stores | 76 // Loads and stores |
| 120 | 77 |
| 121 namespace { | 78 namespace { |
| 122 | 79 |
| 123 struct MemoryAccess { | 80 struct MemoryAccess { |
| 124 MachineType type; | 81 MachineType type; |
| 125 ArchOpcode load_opcode; | 82 ArchOpcode load_opcode; |
| 126 ArchOpcode store_opcode; | 83 ArchOpcode store_opcode; |
| 127 }; | 84 }; |
| 128 | 85 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 EXPECT_EQ(3U, s[0]->InputCount()); | 131 EXPECT_EQ(3U, s[0]->InputCount()); |
| 175 EXPECT_EQ(0U, s[0]->OutputCount()); | 132 EXPECT_EQ(0U, s[0]->OutputCount()); |
| 176 } | 133 } |
| 177 | 134 |
| 178 | 135 |
| 179 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | 136 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, |
| 180 InstructionSelectorMemoryAccessTest, | 137 InstructionSelectorMemoryAccessTest, |
| 181 ::testing::ValuesIn(kMemoryAccesses)); | 138 ::testing::ValuesIn(kMemoryAccesses)); |
| 182 | 139 |
| 183 // ----------------------------------------------------------------------------- | 140 // ----------------------------------------------------------------------------- |
| 184 // AddressingMode for loads and stores. | 141 // ChangeUint32ToUint64. |
| 185 | 142 |
| 186 class AddressingModeUnitTest : public InstructionSelectorTest { | |
| 187 public: | |
| 188 AddressingModeUnitTest() : m(NULL) { Reset(); } | |
| 189 ~AddressingModeUnitTest() { delete m; } | |
| 190 | 143 |
| 191 void Run(Node* base, Node* index, AddressingMode mode) { | 144 namespace { |
| 192 Node* load = m->Load(kMachInt32, base, index); | |
| 193 m->Store(kMachInt32, base, index, load); | |
| 194 m->Return(m->Int32Constant(0)); | |
| 195 Stream s = m->Build(); | |
| 196 ASSERT_EQ(2U, s.size()); | |
| 197 EXPECT_EQ(mode, s[0]->addressing_mode()); | |
| 198 EXPECT_EQ(mode, s[1]->addressing_mode()); | |
| 199 } | |
| 200 | 145 |
| 201 Node* zero; | 146 typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*); |
| 202 Node* null_ptr; | |
| 203 Node* non_zero; | |
| 204 Node* base_reg; // opaque value to generate base as register | |
| 205 Node* index_reg; // opaque value to generate index as register | |
| 206 Node* scales[arraysize(ScaleFactorMatcher::kMatchedFactors)]; | |
| 207 StreamBuilder* m; | |
| 208 | 147 |
| 209 void Reset() { | 148 |
| 210 delete m; | 149 struct BinaryOperation { |
| 211 m = new StreamBuilder(this, kMachInt32, kMachInt32, kMachInt32); | 150 Constructor constructor; |
| 212 zero = m->Int32Constant(0); | 151 const char* constructor_name; |
| 213 null_ptr = m->Int64Constant(0); | |
| 214 non_zero = m->Int32Constant(127); | |
| 215 base_reg = m->Parameter(0); | |
| 216 index_reg = m->Parameter(0); | |
| 217 for (size_t i = 0; i < arraysize(ScaleFactorMatcher::kMatchedFactors); | |
| 218 ++i) { | |
| 219 scales[i] = m->Int32Constant(ScaleFactorMatcher::kMatchedFactors[i]); | |
| 220 } | |
| 221 } | |
| 222 }; | 152 }; |
| 223 | 153 |
| 224 | 154 |
| 225 TEST_F(AddressingModeUnitTest, AddressingMode_MR) { | 155 std::ostream& operator<<(std::ostream& os, const BinaryOperation& bop) { |
| 226 Node* base = base_reg; | 156 return os << bop.constructor_name; |
| 227 Node* index = zero; | |
| 228 Run(base, index, kMode_MR); | |
| 229 } | 157 } |
| 230 | 158 |
| 231 | 159 |
| 232 TEST_F(AddressingModeUnitTest, AddressingMode_MRI) { | 160 const BinaryOperation kWord32BinaryOperations[] = { |
| 233 Node* base = base_reg; | 161 {&RawMachineAssembler::Word32And, "Word32And"}, |
| 234 Node* index = non_zero; | 162 {&RawMachineAssembler::Word32Or, "Word32Or"}, |
| 235 Run(base, index, kMode_MRI); | 163 {&RawMachineAssembler::Word32Xor, "Word32Xor"}, |
| 164 {&RawMachineAssembler::Word32Shl, "Word32Shl"}, |
| 165 {&RawMachineAssembler::Word32Shr, "Word32Shr"}, |
| 166 {&RawMachineAssembler::Word32Sar, "Word32Sar"}, |
| 167 {&RawMachineAssembler::Word32Ror, "Word32Ror"}, |
| 168 {&RawMachineAssembler::Word32Equal, "Word32Equal"}, |
| 169 {&RawMachineAssembler::Int32Add, "Int32Add"}, |
| 170 {&RawMachineAssembler::Int32Sub, "Int32Sub"}, |
| 171 {&RawMachineAssembler::Int32Mul, "Int32Mul"}, |
| 172 {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh"}, |
| 173 {&RawMachineAssembler::Int32Div, "Int32Div"}, |
| 174 {&RawMachineAssembler::Int32LessThan, "Int32LessThan"}, |
| 175 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual"}, |
| 176 {&RawMachineAssembler::Int32Mod, "Int32Mod"}, |
| 177 {&RawMachineAssembler::Uint32Div, "Uint32Div"}, |
| 178 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan"}, |
| 179 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual"}, |
| 180 {&RawMachineAssembler::Uint32Mod, "Uint32Mod"}}; |
| 181 |
| 182 } // namespace |
| 183 |
| 184 |
| 185 typedef InstructionSelectorTestWithParam<BinaryOperation> |
| 186 InstructionSelectorChangeUint32ToUint64Test; |
| 187 |
| 188 |
| 189 TEST_P(InstructionSelectorChangeUint32ToUint64Test, ChangeUint32ToUint64) { |
| 190 const BinaryOperation& bop = GetParam(); |
| 191 StreamBuilder m(this, kMachUint64, kMachInt32, kMachInt32); |
| 192 Node* const p0 = m.Parameter(0); |
| 193 Node* const p1 = m.Parameter(1); |
| 194 m.Return(m.ChangeUint32ToUint64((m.*bop.constructor)(p0, p1))); |
| 195 Stream s = m.Build(); |
| 196 ASSERT_EQ(1U, s.size()); |
| 236 } | 197 } |
| 237 | 198 |
| 238 | 199 |
| 239 TEST_F(AddressingModeUnitTest, AddressingMode_MR1) { | 200 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, |
| 240 Node* base = base_reg; | 201 InstructionSelectorChangeUint32ToUint64Test, |
| 241 Node* index = index_reg; | 202 ::testing::ValuesIn(kWord32BinaryOperations)); |
| 242 Run(base, index, kMode_MR1); | 203 |
| 204 |
| 205 // ----------------------------------------------------------------------------- |
| 206 // TruncateInt64ToInt32. |
| 207 |
| 208 |
| 209 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) { |
| 210 StreamBuilder m(this, kMachInt32, kMachInt64); |
| 211 Node* const p = m.Parameter(0); |
| 212 Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32))); |
| 213 m.Return(t); |
| 214 Stream s = m.Build(); |
| 215 ASSERT_EQ(1U, s.size()); |
| 216 EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); |
| 217 ASSERT_EQ(2U, s[0]->InputCount()); |
| 218 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); |
| 219 EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1))); |
| 220 ASSERT_EQ(1U, s[0]->OutputCount()); |
| 221 EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); |
| 222 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); |
| 243 } | 223 } |
| 244 | 224 |
| 245 | 225 |
| 246 TEST_F(AddressingModeUnitTest, AddressingMode_MRN) { | 226 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) { |
| 247 AddressingMode expected[] = {kMode_MR1, kMode_MR2, kMode_MR4, kMode_MR8}; | 227 StreamBuilder m(this, kMachInt32, kMachInt64); |
| 248 for (size_t i = 0; i < arraysize(scales); ++i) { | 228 Node* const p = m.Parameter(0); |
| 249 Reset(); | 229 Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32))); |
| 250 Node* base = base_reg; | 230 m.Return(t); |
| 251 Node* index = m->Int32Mul(index_reg, scales[i]); | 231 Stream s = m.Build(); |
| 252 Run(base, index, expected[i]); | 232 ASSERT_EQ(1U, s.size()); |
| 253 } | 233 EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); |
| 234 ASSERT_EQ(2U, s[0]->InputCount()); |
| 235 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); |
| 236 EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1))); |
| 237 ASSERT_EQ(1U, s[0]->OutputCount()); |
| 238 EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); |
| 239 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); |
| 254 } | 240 } |
| 255 | 241 |
| 256 | 242 |
| 257 TEST_F(AddressingModeUnitTest, AddressingMode_MR1I) { | 243 // ----------------------------------------------------------------------------- |
| 258 Node* base = base_reg; | 244 // Addition. |
| 259 Node* index = m->Int32Add(index_reg, non_zero); | |
| 260 Run(base, index, kMode_MR1I); | |
| 261 } | |
| 262 | 245 |
| 263 | 246 |
| 264 TEST_F(AddressingModeUnitTest, AddressingMode_MRNI) { | 247 TEST_F(InstructionSelectorTest, Int32AddWithInt32AddWithParameters) { |
| 265 AddressingMode expected[] = {kMode_MR1I, kMode_MR2I, kMode_MR4I, kMode_MR8I}; | 248 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
| 266 for (size_t i = 0; i < arraysize(scales); ++i) { | 249 Node* const p0 = m.Parameter(0); |
| 267 Reset(); | 250 Node* const p1 = m.Parameter(1); |
| 268 Node* base = base_reg; | 251 Node* const a0 = m.Int32Add(p0, p1); |
| 269 Node* index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero); | 252 m.Return(m.Int32Add(a0, p0)); |
| 270 Run(base, index, expected[i]); | 253 Stream s = m.Build(); |
| 271 } | 254 ASSERT_EQ(2U, s.size()); |
| 272 } | 255 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); |
| 273 | 256 ASSERT_EQ(2U, s[0]->InputCount()); |
| 274 | 257 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0))); |
| 275 TEST_F(AddressingModeUnitTest, AddressingMode_M1) { | 258 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); |
| 276 Node* base = null_ptr; | |
| 277 Node* index = index_reg; | |
| 278 Run(base, index, kMode_M1); | |
| 279 } | |
| 280 | |
| 281 | |
| 282 TEST_F(AddressingModeUnitTest, AddressingMode_MN) { | |
| 283 AddressingMode expected[] = {kMode_M1, kMode_M2, kMode_M4, kMode_M8}; | |
| 284 for (size_t i = 0; i < arraysize(scales); ++i) { | |
| 285 Reset(); | |
| 286 Node* base = null_ptr; | |
| 287 Node* index = m->Int32Mul(index_reg, scales[i]); | |
| 288 Run(base, index, expected[i]); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 | |
| 293 TEST_F(AddressingModeUnitTest, AddressingMode_M1I) { | |
| 294 Node* base = null_ptr; | |
| 295 Node* index = m->Int32Add(index_reg, non_zero); | |
| 296 Run(base, index, kMode_M1I); | |
| 297 } | |
| 298 | |
| 299 | |
| 300 TEST_F(AddressingModeUnitTest, AddressingMode_MNI) { | |
| 301 AddressingMode expected[] = {kMode_M1I, kMode_M2I, kMode_M4I, kMode_M8I}; | |
| 302 for (size_t i = 0; i < arraysize(scales); ++i) { | |
| 303 Reset(); | |
| 304 Node* base = null_ptr; | |
| 305 Node* index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero); | |
| 306 Run(base, index, expected[i]); | |
| 307 } | |
| 308 } | 259 } |
| 309 | 260 |
| 310 | 261 |
| 311 // ----------------------------------------------------------------------------- | 262 // ----------------------------------------------------------------------------- |
| 312 // Multiplication. | 263 // Multiplication. |
| 313 | 264 |
| 314 namespace { | |
| 315 | 265 |
| 316 struct MultParam { | 266 TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) { |
| 317 int value; | 267 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
| 318 bool lea_expected; | 268 Node* const p0 = m.Parameter(0); |
| 319 AddressingMode addressing_mode; | 269 Node* const p1 = m.Parameter(1); |
| 320 }; | 270 Node* const m0 = m.Int32Mul(p0, p1); |
| 321 | 271 m.Return(m.Int32Mul(m0, p0)); |
| 322 | 272 Stream s = m.Build(); |
| 323 std::ostream& operator<<(std::ostream& os, const MultParam& m) { | 273 ASSERT_EQ(2U, s.size()); |
| 324 return os << m.value << "." << m.lea_expected << "." << m.addressing_mode; | 274 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); |
| 275 ASSERT_EQ(2U, s[0]->InputCount()); |
| 276 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0))); |
| 277 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); |
| 278 ASSERT_EQ(1U, s[0]->OutputCount()); |
| 279 EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[0]->OutputAt(0))); |
| 280 EXPECT_EQ(kX64Imul32, s[1]->arch_opcode()); |
| 281 ASSERT_EQ(2U, s[1]->InputCount()); |
| 282 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0))); |
| 283 EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[1]->InputAt(1))); |
| 325 } | 284 } |
| 326 | 285 |
| 327 | 286 |
| 328 const MultParam kMultParams[] = {{-1, false, kMode_None}, | |
| 329 {0, false, kMode_None}, | |
| 330 {1, true, kMode_M1}, | |
| 331 {2, true, kMode_M2}, | |
| 332 {3, true, kMode_MR2}, | |
| 333 {4, true, kMode_M4}, | |
| 334 {5, true, kMode_MR4}, | |
| 335 {6, false, kMode_None}, | |
| 336 {7, false, kMode_None}, | |
| 337 {8, true, kMode_M8}, | |
| 338 {9, true, kMode_MR8}, | |
| 339 {10, false, kMode_None}, | |
| 340 {11, false, kMode_None}}; | |
| 341 | |
| 342 } // namespace | |
| 343 | |
| 344 | |
| 345 typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest; | |
| 346 | |
| 347 | |
| 348 static unsigned InputCountForLea(AddressingMode mode) { | |
| 349 switch (mode) { | |
| 350 case kMode_MR1I: | |
| 351 case kMode_MR2I: | |
| 352 case kMode_MR4I: | |
| 353 case kMode_MR8I: | |
| 354 return 3U; | |
| 355 case kMode_M1I: | |
| 356 case kMode_M2I: | |
| 357 case kMode_M4I: | |
| 358 case kMode_M8I: | |
| 359 return 2U; | |
| 360 case kMode_MR1: | |
| 361 case kMode_MR2: | |
| 362 case kMode_MR4: | |
| 363 case kMode_MR8: | |
| 364 return 2U; | |
| 365 case kMode_M1: | |
| 366 case kMode_M2: | |
| 367 case kMode_M4: | |
| 368 case kMode_M8: | |
| 369 return 1U; | |
| 370 default: | |
| 371 UNREACHABLE(); | |
| 372 return 0U; | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 | |
| 377 static AddressingMode AddressingModeForAddMult(const MultParam& m) { | |
| 378 switch (m.addressing_mode) { | |
| 379 case kMode_MR1: | |
| 380 return kMode_MR1I; | |
| 381 case kMode_MR2: | |
| 382 return kMode_MR2I; | |
| 383 case kMode_MR4: | |
| 384 return kMode_MR4I; | |
| 385 case kMode_MR8: | |
| 386 return kMode_MR8I; | |
| 387 case kMode_M1: | |
| 388 return kMode_M1I; | |
| 389 case kMode_M2: | |
| 390 return kMode_M2I; | |
| 391 case kMode_M4: | |
| 392 return kMode_M4I; | |
| 393 case kMode_M8: | |
| 394 return kMode_M8I; | |
| 395 default: | |
| 396 UNREACHABLE(); | |
| 397 return kMode_None; | |
| 398 } | |
| 399 } | |
| 400 | |
| 401 | |
| 402 TEST_P(InstructionSelectorMultTest, Mult32) { | |
| 403 const MultParam m_param = GetParam(); | |
| 404 StreamBuilder m(this, kMachInt32, kMachInt32); | |
| 405 Node* param = m.Parameter(0); | |
| 406 Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value)); | |
| 407 m.Return(mult); | |
| 408 Stream s = m.Build(); | |
| 409 ASSERT_EQ(1U, s.size()); | |
| 410 EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode()); | |
| 411 if (m_param.lea_expected) { | |
| 412 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | |
| 413 ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount()); | |
| 414 } else { | |
| 415 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); | |
| 416 ASSERT_EQ(2U, s[0]->InputCount()); | |
| 417 } | |
| 418 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0))); | |
| 419 } | |
| 420 | |
| 421 | |
| 422 TEST_P(InstructionSelectorMultTest, Mult64) { | |
| 423 const MultParam m_param = GetParam(); | |
| 424 StreamBuilder m(this, kMachInt64, kMachInt64); | |
| 425 Node* param = m.Parameter(0); | |
| 426 Node* mult = m.Int64Mul(param, m.Int64Constant(m_param.value)); | |
| 427 m.Return(mult); | |
| 428 Stream s = m.Build(); | |
| 429 ASSERT_EQ(1U, s.size()); | |
| 430 EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode()); | |
| 431 if (m_param.lea_expected) { | |
| 432 EXPECT_EQ(kX64Lea, s[0]->arch_opcode()); | |
| 433 ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount()); | |
| 434 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0))); | |
| 435 } else { | |
| 436 EXPECT_EQ(kX64Imul, s[0]->arch_opcode()); | |
| 437 ASSERT_EQ(2U, s[0]->InputCount()); | |
| 438 // TODO(dcarney): why is this happening? | |
| 439 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(1))); | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 | |
| 444 TEST_P(InstructionSelectorMultTest, MultAdd32) { | |
| 445 TRACED_FOREACH(int32_t, imm, kImmediates) { | |
| 446 const MultParam m_param = GetParam(); | |
| 447 StreamBuilder m(this, kMachInt32, kMachInt32); | |
| 448 Node* param = m.Parameter(0); | |
| 449 Node* mult = m.Int32Add(m.Int32Mul(param, m.Int32Constant(m_param.value)), | |
| 450 m.Int32Constant(imm)); | |
| 451 m.Return(mult); | |
| 452 Stream s = m.Build(); | |
| 453 if (m_param.lea_expected) { | |
| 454 ASSERT_EQ(1U, s.size()); | |
| 455 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | |
| 456 EXPECT_EQ(AddressingModeForAddMult(m_param), s[0]->addressing_mode()); | |
| 457 unsigned input_count = InputCountForLea(s[0]->addressing_mode()); | |
| 458 ASSERT_EQ(input_count, s[0]->InputCount()); | |
| 459 ASSERT_EQ(InstructionOperand::IMMEDIATE, | |
| 460 s[0]->InputAt(input_count - 1)->kind()); | |
| 461 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1))); | |
| 462 } else { | |
| 463 ASSERT_EQ(2U, s.size()); | |
| 464 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); | |
| 465 EXPECT_EQ(kX64Add32, s[1]->arch_opcode()); | |
| 466 } | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 | |
| 471 TEST_P(InstructionSelectorMultTest, MultAdd64) { | |
| 472 TRACED_FOREACH(int32_t, imm, kImmediates) { | |
| 473 const MultParam m_param = GetParam(); | |
| 474 StreamBuilder m(this, kMachInt64, kMachInt64); | |
| 475 Node* param = m.Parameter(0); | |
| 476 Node* mult = m.Int64Add(m.Int64Mul(param, m.Int64Constant(m_param.value)), | |
| 477 m.Int64Constant(imm)); | |
| 478 m.Return(mult); | |
| 479 Stream s = m.Build(); | |
| 480 if (m_param.lea_expected) { | |
| 481 ASSERT_EQ(1U, s.size()); | |
| 482 EXPECT_EQ(kX64Lea, s[0]->arch_opcode()); | |
| 483 EXPECT_EQ(AddressingModeForAddMult(m_param), s[0]->addressing_mode()); | |
| 484 unsigned input_count = InputCountForLea(s[0]->addressing_mode()); | |
| 485 ASSERT_EQ(input_count, s[0]->InputCount()); | |
| 486 ASSERT_EQ(InstructionOperand::IMMEDIATE, | |
| 487 s[0]->InputAt(input_count - 1)->kind()); | |
| 488 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1))); | |
| 489 } else { | |
| 490 ASSERT_EQ(2U, s.size()); | |
| 491 EXPECT_EQ(kX64Imul, s[0]->arch_opcode()); | |
| 492 EXPECT_EQ(kX64Add, s[1]->arch_opcode()); | |
| 493 } | |
| 494 } | |
| 495 } | |
| 496 | |
| 497 | |
| 498 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest, | |
| 499 ::testing::ValuesIn(kMultParams)); | |
| 500 | |
| 501 | |
| 502 TEST_F(InstructionSelectorTest, Int32MulHigh) { | 287 TEST_F(InstructionSelectorTest, Int32MulHigh) { |
| 503 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | 288 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
| 504 Node* const p0 = m.Parameter(0); | 289 Node* const p0 = m.Parameter(0); |
| 505 Node* const p1 = m.Parameter(1); | 290 Node* const p1 = m.Parameter(1); |
| 506 Node* const n = m.Int32MulHigh(p0, p1); | 291 Node* const n = m.Int32MulHigh(p0, p1); |
| 507 m.Return(n); | 292 m.Return(n); |
| 508 Stream s = m.Build(); | 293 Stream s = m.Build(); |
| 509 ASSERT_EQ(1U, s.size()); | 294 ASSERT_EQ(1U, s.size()); |
| 510 EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode()); | 295 EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode()); |
| 511 ASSERT_EQ(2U, s[0]->InputCount()); | 296 ASSERT_EQ(2U, s[0]->InputCount()); |
| 512 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 297 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
| 513 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax)); | 298 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax)); |
| 514 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); | 299 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); |
| 515 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); | 300 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); |
| 516 ASSERT_EQ(1U, s[0]->OutputCount()); | 301 ASSERT_EQ(1U, s[0]->OutputCount()); |
| 517 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); | 302 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); |
| 518 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx)); | 303 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx)); |
| 519 } | 304 } |
| 520 | 305 |
| 521 } // namespace compiler | 306 } // namespace compiler |
| 522 } // namespace internal | 307 } // namespace internal |
| 523 } // namespace v8 | 308 } // namespace v8 |
| OLD | NEW |