OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/compiler/instruction-selector-unittest.h" | |
6 #include "src/compiler/node-matchers.h" | |
7 | |
8 namespace v8 { | |
9 namespace internal { | |
10 namespace compiler { | |
11 | |
12 // ----------------------------------------------------------------------------- | |
13 // Conversions. | |
14 | |
15 | |
16 TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) { | |
17 StreamBuilder m(this, kMachFloat32, kMachFloat64); | |
18 m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0))); | |
19 Stream s = m.Build(); | |
20 ASSERT_EQ(1U, s.size()); | |
21 EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode()); | |
22 EXPECT_EQ(1U, s[0]->InputCount()); | |
23 EXPECT_EQ(1U, s[0]->OutputCount()); | |
24 } | |
25 | |
26 | |
27 TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) { | |
28 StreamBuilder m(this, kMachInt64, kMachInt32); | |
29 m.Return(m.ChangeInt32ToInt64(m.Parameter(0))); | |
30 Stream s = m.Build(); | |
31 ASSERT_EQ(1U, s.size()); | |
32 EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode()); | |
33 } | |
34 | |
35 | |
36 TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) { | |
37 StreamBuilder m(this, kMachFloat64, kMachUint32); | |
38 m.Return(m.ChangeUint32ToFloat64(m.Parameter(0))); | |
39 Stream s = m.Build(); | |
40 ASSERT_EQ(1U, s.size()); | |
41 EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode()); | |
42 } | |
43 | |
44 | |
45 TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) { | |
46 StreamBuilder m(this, kMachUint64, kMachUint32); | |
47 m.Return(m.ChangeUint32ToUint64(m.Parameter(0))); | |
48 Stream s = m.Build(); | |
49 ASSERT_EQ(1U, s.size()); | |
50 EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); | |
51 } | |
52 | |
53 | |
54 TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) { | |
55 StreamBuilder m(this, kMachFloat64, kMachFloat32); | |
56 m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0))); | |
57 Stream s = m.Build(); | |
58 ASSERT_EQ(1U, s.size()); | |
59 EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode()); | |
60 EXPECT_EQ(1U, s[0]->InputCount()); | |
61 EXPECT_EQ(1U, s[0]->OutputCount()); | |
62 } | |
63 | |
64 | |
65 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) { | |
66 StreamBuilder m(this, kMachInt32, kMachInt64); | |
67 m.Return(m.TruncateInt64ToInt32(m.Parameter(0))); | |
68 Stream s = m.Build(); | |
69 ASSERT_EQ(1U, s.size()); | |
70 EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); | |
71 } | |
72 | |
73 | |
74 // ----------------------------------------------------------------------------- | |
75 // Better left operand for commutative binops | |
76 | |
77 TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) { | |
78 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | |
79 Node* param1 = m.Parameter(0); | |
80 Node* param2 = m.Parameter(1); | |
81 Node* add = m.Int32Add(param1, param2); | |
82 m.Return(m.Int32Add(add, param1)); | |
83 Stream s = m.Build(); | |
84 ASSERT_EQ(2U, s.size()); | |
85 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); | |
86 ASSERT_EQ(2U, s[0]->InputCount()); | |
87 ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated()); | |
88 EXPECT_EQ(param2->id(), s.ToVreg(s[0]->InputAt(0))); | |
89 } | |
90 | |
91 | |
92 TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) { | |
93 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | |
94 Node* param1 = m.Parameter(0); | |
95 Node* param2 = m.Parameter(1); | |
96 Node* mul = m.Int32Mul(param1, param2); | |
97 m.Return(m.Int32Mul(mul, param1)); | |
98 Stream s = m.Build(); | |
99 ASSERT_EQ(2U, s.size()); | |
100 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); | |
101 ASSERT_EQ(2U, s[0]->InputCount()); | |
102 ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated()); | |
103 EXPECT_EQ(param2->id(), s.ToVreg(s[0]->InputAt(0))); | |
104 } | |
105 | |
106 | |
107 // ----------------------------------------------------------------------------- | |
108 // Loads and stores | |
109 | |
110 namespace { | |
111 | |
112 struct MemoryAccess { | |
113 MachineType type; | |
114 ArchOpcode load_opcode; | |
115 ArchOpcode store_opcode; | |
116 }; | |
117 | |
118 | |
119 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { | |
120 return os << memacc.type; | |
121 } | |
122 | |
123 | |
124 static const MemoryAccess kMemoryAccesses[] = { | |
125 {kMachInt8, kX64Movsxbl, kX64Movb}, | |
126 {kMachUint8, kX64Movzxbl, kX64Movb}, | |
127 {kMachInt16, kX64Movsxwl, kX64Movw}, | |
128 {kMachUint16, kX64Movzxwl, kX64Movw}, | |
129 {kMachInt32, kX64Movl, kX64Movl}, | |
130 {kMachUint32, kX64Movl, kX64Movl}, | |
131 {kMachInt64, kX64Movq, kX64Movq}, | |
132 {kMachUint64, kX64Movq, kX64Movq}, | |
133 {kMachFloat32, kX64Movss, kX64Movss}, | |
134 {kMachFloat64, kX64Movsd, kX64Movsd}}; | |
135 | |
136 } // namespace | |
137 | |
138 | |
139 typedef InstructionSelectorTestWithParam<MemoryAccess> | |
140 InstructionSelectorMemoryAccessTest; | |
141 | |
142 | |
143 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { | |
144 const MemoryAccess memacc = GetParam(); | |
145 StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); | |
146 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); | |
147 Stream s = m.Build(); | |
148 ASSERT_EQ(1U, s.size()); | |
149 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); | |
150 EXPECT_EQ(2U, s[0]->InputCount()); | |
151 EXPECT_EQ(1U, s[0]->OutputCount()); | |
152 } | |
153 | |
154 | |
155 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { | |
156 const MemoryAccess memacc = GetParam(); | |
157 StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); | |
158 m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); | |
159 m.Return(m.Int32Constant(0)); | |
160 Stream s = m.Build(); | |
161 ASSERT_EQ(1U, s.size()); | |
162 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); | |
163 EXPECT_EQ(3U, s[0]->InputCount()); | |
164 EXPECT_EQ(0U, s[0]->OutputCount()); | |
165 } | |
166 | |
167 | |
168 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
169 InstructionSelectorMemoryAccessTest, | |
170 ::testing::ValuesIn(kMemoryAccesses)); | |
171 | |
172 // ----------------------------------------------------------------------------- | |
173 // AddressingMode for loads and stores. | |
174 | |
175 class AddressingModeUnitTest : public InstructionSelectorTest { | |
176 public: | |
177 AddressingModeUnitTest() : m(NULL) { Reset(); } | |
178 ~AddressingModeUnitTest() { delete m; } | |
179 | |
180 void Run(Node* base, Node* index, AddressingMode mode) { | |
181 Node* load = m->Load(kMachInt32, base, index); | |
182 m->Store(kMachInt32, base, index, load); | |
183 m->Return(m->Int32Constant(0)); | |
184 Stream s = m->Build(); | |
185 ASSERT_EQ(2U, s.size()); | |
186 EXPECT_EQ(mode, s[0]->addressing_mode()); | |
187 EXPECT_EQ(mode, s[1]->addressing_mode()); | |
188 } | |
189 | |
190 Node* zero; | |
191 Node* null_ptr; | |
192 Node* non_zero; | |
193 Node* base_reg; // opaque value to generate base as register | |
194 Node* index_reg; // opaque value to generate index as register | |
195 Node* scales[arraysize(ScaleFactorMatcher::kMatchedFactors)]; | |
196 StreamBuilder* m; | |
197 | |
198 void Reset() { | |
199 delete m; | |
200 m = new StreamBuilder(this, kMachInt32, kMachInt32, kMachInt32); | |
201 zero = m->Int32Constant(0); | |
202 null_ptr = m->Int64Constant(0); | |
203 non_zero = m->Int32Constant(127); | |
204 base_reg = m->Parameter(0); | |
205 index_reg = m->Parameter(0); | |
206 for (size_t i = 0; i < arraysize(ScaleFactorMatcher::kMatchedFactors); | |
207 ++i) { | |
208 scales[i] = m->Int32Constant(ScaleFactorMatcher::kMatchedFactors[i]); | |
209 } | |
210 } | |
211 }; | |
212 | |
213 | |
214 TEST_F(AddressingModeUnitTest, AddressingMode_MR) { | |
215 Node* base = base_reg; | |
216 Node* index = zero; | |
217 Run(base, index, kMode_MR); | |
218 } | |
219 | |
220 | |
221 TEST_F(AddressingModeUnitTest, AddressingMode_MRI) { | |
222 Node* base = base_reg; | |
223 Node* index = non_zero; | |
224 Run(base, index, kMode_MRI); | |
225 } | |
226 | |
227 | |
228 TEST_F(AddressingModeUnitTest, AddressingMode_MR1) { | |
229 Node* base = base_reg; | |
230 Node* index = index_reg; | |
231 Run(base, index, kMode_MR1); | |
232 } | |
233 | |
234 | |
235 TEST_F(AddressingModeUnitTest, AddressingMode_MRN) { | |
236 AddressingMode expected[] = {kMode_MR1, kMode_MR2, kMode_MR4, kMode_MR8}; | |
237 for (size_t i = 0; i < arraysize(scales); ++i) { | |
238 Reset(); | |
239 Node* base = base_reg; | |
240 Node* index = m->Int32Mul(index_reg, scales[i]); | |
241 Run(base, index, expected[i]); | |
242 } | |
243 } | |
244 | |
245 | |
246 TEST_F(AddressingModeUnitTest, AddressingMode_MR1I) { | |
247 Node* base = base_reg; | |
248 Node* index = m->Int32Add(index_reg, non_zero); | |
249 Run(base, index, kMode_MR1I); | |
250 } | |
251 | |
252 | |
253 TEST_F(AddressingModeUnitTest, AddressingMode_MRNI) { | |
254 AddressingMode expected[] = {kMode_MR1I, kMode_MR2I, kMode_MR4I, kMode_MR8I}; | |
255 for (size_t i = 0; i < arraysize(scales); ++i) { | |
256 Reset(); | |
257 Node* base = base_reg; | |
258 Node* index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero); | |
259 Run(base, index, expected[i]); | |
260 } | |
261 } | |
262 | |
263 | |
264 TEST_F(AddressingModeUnitTest, AddressingMode_M1) { | |
265 Node* base = null_ptr; | |
266 Node* index = index_reg; | |
267 Run(base, index, kMode_M1); | |
268 } | |
269 | |
270 | |
271 TEST_F(AddressingModeUnitTest, AddressingMode_MN) { | |
272 AddressingMode expected[] = {kMode_M1, kMode_M2, kMode_M4, kMode_M8}; | |
273 for (size_t i = 0; i < arraysize(scales); ++i) { | |
274 Reset(); | |
275 Node* base = null_ptr; | |
276 Node* index = m->Int32Mul(index_reg, scales[i]); | |
277 Run(base, index, expected[i]); | |
278 } | |
279 } | |
280 | |
281 | |
282 TEST_F(AddressingModeUnitTest, AddressingMode_M1I) { | |
283 Node* base = null_ptr; | |
284 Node* index = m->Int32Add(index_reg, non_zero); | |
285 Run(base, index, kMode_M1I); | |
286 } | |
287 | |
288 | |
289 TEST_F(AddressingModeUnitTest, AddressingMode_MNI) { | |
290 AddressingMode expected[] = {kMode_M1I, kMode_M2I, kMode_M4I, kMode_M8I}; | |
291 for (size_t i = 0; i < arraysize(scales); ++i) { | |
292 Reset(); | |
293 Node* base = null_ptr; | |
294 Node* index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero); | |
295 Run(base, index, expected[i]); | |
296 } | |
297 } | |
298 | |
299 | |
300 // ----------------------------------------------------------------------------- | |
301 // Multiplication. | |
302 | |
303 namespace { | |
304 | |
305 struct MultParam { | |
306 int value; | |
307 bool lea_expected; | |
308 AddressingMode addressing_mode; | |
309 }; | |
310 | |
311 | |
312 std::ostream& operator<<(std::ostream& os, const MultParam& m) { | |
313 return os << m.value << "." << m.lea_expected << "." << m.addressing_mode; | |
314 } | |
315 | |
316 | |
317 const MultParam kMultParams[] = {{-1, false, kMode_None}, | |
318 {0, false, kMode_None}, | |
319 {1, true, kMode_M1}, | |
320 {2, true, kMode_M2}, | |
321 {3, true, kMode_MR2}, | |
322 {4, true, kMode_M4}, | |
323 {5, true, kMode_MR4}, | |
324 {6, false, kMode_None}, | |
325 {7, false, kMode_None}, | |
326 {8, true, kMode_M8}, | |
327 {9, true, kMode_MR8}, | |
328 {10, false, kMode_None}, | |
329 {11, false, kMode_None}}; | |
330 | |
331 } // namespace | |
332 | |
333 | |
334 typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest; | |
335 | |
336 | |
337 static unsigned InputCountForLea(AddressingMode mode) { | |
338 switch (mode) { | |
339 case kMode_MR1: | |
340 case kMode_MR2: | |
341 case kMode_MR4: | |
342 case kMode_MR8: | |
343 return 2U; | |
344 case kMode_M1: | |
345 case kMode_M2: | |
346 case kMode_M4: | |
347 case kMode_M8: | |
348 return 1U; | |
349 default: | |
350 UNREACHABLE(); | |
351 return 0U; | |
352 } | |
353 } | |
354 | |
355 | |
356 TEST_P(InstructionSelectorMultTest, Mult32) { | |
357 const MultParam m_param = GetParam(); | |
358 StreamBuilder m(this, kMachInt32, kMachInt32); | |
359 Node* param = m.Parameter(0); | |
360 Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value)); | |
361 m.Return(mult); | |
362 Stream s = m.Build(); | |
363 ASSERT_EQ(1U, s.size()); | |
364 EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode()); | |
365 if (m_param.lea_expected) { | |
366 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | |
367 ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount()); | |
368 } else { | |
369 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); | |
370 ASSERT_EQ(2U, s[0]->InputCount()); | |
371 } | |
372 EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(0))); | |
373 } | |
374 | |
375 | |
376 TEST_P(InstructionSelectorMultTest, Mult64) { | |
377 const MultParam m_param = GetParam(); | |
378 StreamBuilder m(this, kMachInt64, kMachInt64); | |
379 Node* param = m.Parameter(0); | |
380 Node* mult = m.Int64Mul(param, m.Int64Constant(m_param.value)); | |
381 m.Return(mult); | |
382 Stream s = m.Build(); | |
383 ASSERT_EQ(1U, s.size()); | |
384 EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode()); | |
385 if (m_param.lea_expected) { | |
386 EXPECT_EQ(kX64Lea, s[0]->arch_opcode()); | |
387 ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount()); | |
388 EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(0))); | |
389 } else { | |
390 EXPECT_EQ(kX64Imul, s[0]->arch_opcode()); | |
391 ASSERT_EQ(2U, s[0]->InputCount()); | |
392 // TODO(dcarney): why is this happening? | |
393 EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(1))); | |
394 } | |
395 } | |
396 | |
397 | |
398 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest, | |
399 ::testing::ValuesIn(kMultParams)); | |
400 | |
401 } // namespace compiler | |
402 } // namespace internal | |
403 } // namespace v8 | |
OLD | NEW |