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 |