blob: 2dc30294a29cd6223cde2de2894f174c16d9667b [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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 <limits>
6
7#include "src/v8.h"
8#include "test/cctest/cctest.h"
9#include "test/cctest/compiler/graph-builder-tester.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010#include "test/cctest/compiler/value-helper.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011
12#include "src/compiler/node-matchers.h"
13#include "src/compiler/representation-change.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014
15using namespace v8::internal;
16using namespace v8::internal::compiler;
17
18namespace v8 { // for friendiness.
19namespace internal {
20namespace compiler {
21
22class RepresentationChangerTester : public HandleAndZoneScope,
23 public GraphAndBuilders {
24 public:
25 explicit RepresentationChangerTester(int num_parameters = 0)
26 : GraphAndBuilders(main_zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 javascript_(main_zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028 jsgraph_(main_graph_, &main_common_, &javascript_, &main_machine_),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029 changer_(&jsgraph_, &main_simplified_, main_isolate()) {
30 Node* s = graph()->NewNode(common()->Start(num_parameters));
31 graph()->SetStart(s);
32 }
33
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034 JSOperatorBuilder javascript_;
35 JSGraph jsgraph_;
36 RepresentationChanger changer_;
37
38 Isolate* isolate() { return main_isolate(); }
39 Graph* graph() { return main_graph_; }
40 CommonOperatorBuilder* common() { return &main_common_; }
41 JSGraph* jsgraph() { return &jsgraph_; }
42 RepresentationChanger* changer() { return &changer_; }
43
44 // TODO(titzer): use ValueChecker / ValueUtil
45 void CheckInt32Constant(Node* n, int32_t expected) {
46 Int32Matcher m(n);
47 CHECK(m.HasValue());
48 CHECK_EQ(expected, m.Value());
49 }
50
Emily Bernierd0a1eb72015-03-24 16:35:39 -040051 void CheckUint32Constant(Node* n, uint32_t expected) {
52 Uint32Matcher m(n);
53 CHECK(m.HasValue());
54 CHECK_EQ(static_cast<int>(expected), static_cast<int>(m.Value()));
55 }
56
57 void CheckFloat64Constant(Node* n, double expected) {
58 Float64Matcher m(n);
59 CHECK(m.HasValue());
60 CHECK_EQ(expected, m.Value());
61 }
62
63 void CheckFloat32Constant(Node* n, float expected) {
64 CHECK_EQ(IrOpcode::kFloat32Constant, n->opcode());
65 float fval = OpParameter<float>(n->op());
66 CHECK_EQ(expected, fval);
67 }
68
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 void CheckHeapConstant(Node* n, HeapObject* expected) {
70 HeapObjectMatcher<HeapObject> m(n);
71 CHECK(m.HasValue());
72 CHECK_EQ(expected, *m.Value().handle());
73 }
74
75 void CheckNumberConstant(Node* n, double expected) {
76 NumberMatcher m(n);
77 CHECK_EQ(IrOpcode::kNumberConstant, n->opcode());
78 CHECK(m.HasValue());
79 CHECK_EQ(expected, m.Value());
80 }
81
82 Node* Parameter(int index = 0) {
83 return graph()->NewNode(common()->Parameter(index), graph()->start());
84 }
85
86 void CheckTypeError(MachineTypeUnion from, MachineTypeUnion to) {
87 changer()->testing_type_errors_ = true;
88 changer()->type_error_ = false;
89 Node* n = Parameter(0);
90 Node* c = changer()->GetRepresentationFor(n, from, to);
91 CHECK(changer()->type_error_);
92 CHECK_EQ(n, c);
93 }
94
95 void CheckNop(MachineTypeUnion from, MachineTypeUnion to) {
96 Node* n = Parameter(0);
97 Node* c = changer()->GetRepresentationFor(n, from, to);
98 CHECK_EQ(n, c);
99 }
100};
101}
102}
103} // namespace v8::internal::compiler
104
105
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400106static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
107 kRepFloat32, kRepFloat64, kRepTagged};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108
109
110TEST(BoolToBit_constant) {
111 RepresentationChangerTester r;
112
113 Node* true_node = r.jsgraph()->TrueConstant();
114 Node* true_bit =
115 r.changer()->GetRepresentationFor(true_node, kRepTagged, kRepBit);
116 r.CheckInt32Constant(true_bit, 1);
117
118 Node* false_node = r.jsgraph()->FalseConstant();
119 Node* false_bit =
120 r.changer()->GetRepresentationFor(false_node, kRepTagged, kRepBit);
121 r.CheckInt32Constant(false_bit, 0);
122}
123
124
125TEST(BitToBool_constant) {
126 RepresentationChangerTester r;
127
128 for (int i = -5; i < 5; i++) {
129 Node* node = r.jsgraph()->Int32Constant(i);
130 Node* val = r.changer()->GetRepresentationFor(node, kRepBit, kRepTagged);
131 r.CheckHeapConstant(val, i == 0 ? r.isolate()->heap()->false_value()
132 : r.isolate()->heap()->true_value());
133 }
134}
135
136
137TEST(ToTagged_constant) {
138 RepresentationChangerTester r;
139
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400140 {
141 FOR_FLOAT64_INPUTS(i) {
142 Node* n = r.jsgraph()->Float64Constant(*i);
143 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
144 r.CheckNumberConstant(c, *i);
145 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 }
147
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400148 {
149 FOR_FLOAT64_INPUTS(i) {
150 Node* n = r.jsgraph()->Constant(*i);
151 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
152 r.CheckNumberConstant(c, *i);
153 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 }
155
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400156 {
157 FOR_FLOAT32_INPUTS(i) {
158 Node* n = r.jsgraph()->Float32Constant(*i);
159 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged);
160 r.CheckNumberConstant(c, *i);
161 }
162 }
163
164 {
165 FOR_INT32_INPUTS(i) {
166 Node* n = r.jsgraph()->Int32Constant(*i);
167 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
168 kRepTagged);
169 r.CheckNumberConstant(c, *i);
170 }
171 }
172
173 {
174 FOR_UINT32_INPUTS(i) {
175 Node* n = r.jsgraph()->Int32Constant(*i);
176 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
177 kRepTagged);
178 r.CheckNumberConstant(c, *i);
179 }
180 }
181}
182
183
184TEST(ToFloat64_constant) {
185 RepresentationChangerTester r;
186
187 {
188 FOR_FLOAT64_INPUTS(i) {
189 Node* n = r.jsgraph()->Float64Constant(*i);
190 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat64);
191 CHECK_EQ(n, c);
192 }
193 }
194
195 {
196 FOR_FLOAT64_INPUTS(i) {
197 Node* n = r.jsgraph()->Constant(*i);
198 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat64);
199 r.CheckFloat64Constant(c, *i);
200 }
201 }
202
203 {
204 FOR_FLOAT32_INPUTS(i) {
205 Node* n = r.jsgraph()->Float32Constant(*i);
206 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat64);
207 r.CheckFloat64Constant(c, *i);
208 }
209 }
210
211 {
212 FOR_INT32_INPUTS(i) {
213 Node* n = r.jsgraph()->Int32Constant(*i);
214 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
215 kRepFloat64);
216 r.CheckFloat64Constant(c, *i);
217 }
218 }
219
220 {
221 FOR_UINT32_INPUTS(i) {
222 Node* n = r.jsgraph()->Int32Constant(*i);
223 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
224 kRepFloat64);
225 r.CheckFloat64Constant(c, *i);
226 }
227 }
228}
229
230
231static bool IsFloat32Int32(int32_t val) {
232 return val >= -(1 << 23) && val <= (1 << 23);
233}
234
235
236static bool IsFloat32Uint32(uint32_t val) { return val <= (1 << 23); }
237
238
239TEST(ToFloat32_constant) {
240 RepresentationChangerTester r;
241
242 {
243 FOR_FLOAT32_INPUTS(i) {
244 Node* n = r.jsgraph()->Float32Constant(*i);
245 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat32);
246 CHECK_EQ(n, c);
247 }
248 }
249
250 {
251 FOR_FLOAT32_INPUTS(i) {
252 Node* n = r.jsgraph()->Constant(*i);
253 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat32);
254 r.CheckFloat32Constant(c, *i);
255 }
256 }
257
258 {
259 FOR_FLOAT32_INPUTS(i) {
260 Node* n = r.jsgraph()->Float64Constant(*i);
261 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat32);
262 r.CheckFloat32Constant(c, *i);
263 }
264 }
265
266 {
267 FOR_INT32_INPUTS(i) {
268 if (!IsFloat32Int32(*i)) continue;
269 Node* n = r.jsgraph()->Int32Constant(*i);
270 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
271 kRepFloat32);
272 r.CheckFloat32Constant(c, static_cast<float>(*i));
273 }
274 }
275
276 {
277 FOR_UINT32_INPUTS(i) {
278 if (!IsFloat32Uint32(*i)) continue;
279 Node* n = r.jsgraph()->Int32Constant(*i);
280 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
281 kRepFloat32);
282 r.CheckFloat32Constant(c, static_cast<float>(*i));
283 }
284 }
285}
286
287
288TEST(ToInt32_constant) {
289 RepresentationChangerTester r;
290
291 {
292 FOR_INT32_INPUTS(i) {
293 Node* n = r.jsgraph()->Int32Constant(*i);
294 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
295 kRepWord32);
296 r.CheckInt32Constant(c, *i);
297 }
298 }
299
300 {
301 FOR_INT32_INPUTS(i) {
302 if (!IsFloat32Int32(*i)) continue;
303 Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
304 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeInt32,
305 kRepWord32);
306 r.CheckInt32Constant(c, *i);
307 }
308 }
309
310 {
311 FOR_INT32_INPUTS(i) {
312 Node* n = r.jsgraph()->Float64Constant(*i);
313 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeInt32,
314 kRepWord32);
315 r.CheckInt32Constant(c, *i);
316 }
317 }
318
319 {
320 FOR_INT32_INPUTS(i) {
321 Node* n = r.jsgraph()->Constant(*i);
322 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeInt32,
323 kRepWord32);
324 r.CheckInt32Constant(c, *i);
325 }
326 }
327}
328
329
330TEST(ToUint32_constant) {
331 RepresentationChangerTester r;
332
333 {
334 FOR_UINT32_INPUTS(i) {
335 Node* n = r.jsgraph()->Int32Constant(*i);
336 Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
337 kRepWord32);
338 r.CheckUint32Constant(c, *i);
339 }
340 }
341
342 {
343 FOR_UINT32_INPUTS(i) {
344 if (!IsFloat32Uint32(*i)) continue;
345 Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
346 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeUint32,
347 kRepWord32);
348 r.CheckUint32Constant(c, *i);
349 }
350 }
351
352 {
353 FOR_UINT32_INPUTS(i) {
354 Node* n = r.jsgraph()->Float64Constant(*i);
355 Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeUint32,
356 kRepWord32);
357 r.CheckUint32Constant(c, *i);
358 }
359 }
360
361 {
362 FOR_UINT32_INPUTS(i) {
363 Node* n = r.jsgraph()->Constant(static_cast<double>(*i));
364 Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeUint32,
365 kRepWord32);
366 r.CheckUint32Constant(c, *i);
367 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368 }
369}
370
371
372static void CheckChange(IrOpcode::Value expected, MachineTypeUnion from,
373 MachineTypeUnion to) {
374 RepresentationChangerTester r;
375
376 Node* n = r.Parameter();
377 Node* c = r.changer()->GetRepresentationFor(n, from, to);
378
379 CHECK_NE(c, n);
380 CHECK_EQ(expected, c->opcode());
381 CHECK_EQ(n, c->InputAt(0));
382}
383
384
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400385static void CheckTwoChanges(IrOpcode::Value expected2,
386 IrOpcode::Value expected1, MachineTypeUnion from,
387 MachineTypeUnion to) {
388 RepresentationChangerTester r;
389
390 Node* n = r.Parameter();
391 Node* c1 = r.changer()->GetRepresentationFor(n, from, to);
392
393 CHECK_NE(c1, n);
394 CHECK_EQ(expected1, c1->opcode());
395 Node* c2 = c1->InputAt(0);
396 CHECK_NE(c2, n);
397 CHECK_EQ(expected2, c2->opcode());
398 CHECK_EQ(n, c2->InputAt(0));
399}
400
401
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000402TEST(SingleChanges) {
403 CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit);
404 CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged);
405
406 CheckChange(IrOpcode::kChangeInt32ToTagged, kRepWord32 | kTypeInt32,
407 kRepTagged);
408 CheckChange(IrOpcode::kChangeUint32ToTagged, kRepWord32 | kTypeUint32,
409 kRepTagged);
410 CheckChange(IrOpcode::kChangeFloat64ToTagged, kRepFloat64, kRepTagged);
411
412 CheckChange(IrOpcode::kChangeTaggedToInt32, kRepTagged | kTypeInt32,
413 kRepWord32);
414 CheckChange(IrOpcode::kChangeTaggedToUint32, kRepTagged | kTypeUint32,
415 kRepWord32);
416 CheckChange(IrOpcode::kChangeTaggedToFloat64, kRepTagged, kRepFloat64);
417
418 // Int32,Uint32 <-> Float64 are actually machine conversions.
419 CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32 | kTypeInt32,
420 kRepFloat64);
421 CheckChange(IrOpcode::kChangeUint32ToFloat64, kRepWord32 | kTypeUint32,
422 kRepFloat64);
423 CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64 | kTypeInt32,
424 kRepWord32);
425 CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32,
426 kRepWord32);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400427
428 CheckChange(IrOpcode::kTruncateFloat64ToFloat32, kRepFloat64, kRepFloat32);
429
430 // Int32,Uint32 <-> Float32 require two changes.
431 CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
432 IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeInt32,
433 kRepFloat32);
434 CheckTwoChanges(IrOpcode::kChangeUint32ToFloat64,
435 IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeUint32,
436 kRepFloat32);
437 CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
438 IrOpcode::kChangeFloat64ToInt32, kRepFloat32 | kTypeInt32,
439 kRepWord32);
440 CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
441 IrOpcode::kChangeFloat64ToUint32, kRepFloat32 | kTypeUint32,
442 kRepWord32);
443
444 // Float32 <-> Tagged require two changes.
445 CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
446 IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged);
447 CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64,
448 IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449}
450
451
452TEST(SignednessInWord32) {
453 RepresentationChangerTester r;
454
455 // TODO(titzer): assume that uses of a word32 without a sign mean kTypeInt32.
456 CheckChange(IrOpcode::kChangeTaggedToInt32, kRepTagged,
457 kRepWord32 | kTypeInt32);
458 CheckChange(IrOpcode::kChangeTaggedToUint32, kRepTagged,
459 kRepWord32 | kTypeUint32);
460 CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
461 CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400462
463 CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
464 IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32);
465 CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
466 IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000467}
468
469
470TEST(Nops) {
471 RepresentationChangerTester r;
472
473 // X -> X is always a nop for any single representation X.
474 for (size_t i = 0; i < arraysize(all_reps); i++) {
475 r.CheckNop(all_reps[i], all_reps[i]);
476 }
477
478 // 32-bit floats.
479 r.CheckNop(kRepFloat32, kRepFloat32);
480 r.CheckNop(kRepFloat32 | kTypeNumber, kRepFloat32);
481 r.CheckNop(kRepFloat32, kRepFloat32 | kTypeNumber);
482
483 // 32-bit or 64-bit words can be used as branch conditions (kRepBit).
484 r.CheckNop(kRepWord32, kRepBit);
485 r.CheckNop(kRepWord32, kRepBit | kTypeBool);
486 r.CheckNop(kRepWord64, kRepBit);
487 r.CheckNop(kRepWord64, kRepBit | kTypeBool);
488
489 // 32-bit words can be used as smaller word sizes and vice versa, because
490 // loads from memory implicitly sign or zero extend the value to the
491 // full machine word size, and stores implicitly truncate.
492 r.CheckNop(kRepWord32, kRepWord8);
493 r.CheckNop(kRepWord32, kRepWord16);
494 r.CheckNop(kRepWord32, kRepWord32);
495 r.CheckNop(kRepWord8, kRepWord32);
496 r.CheckNop(kRepWord16, kRepWord32);
497
498 // kRepBit (result of comparison) is implicitly a wordish thing.
499 r.CheckNop(kRepBit, kRepWord8);
500 r.CheckNop(kRepBit | kTypeBool, kRepWord8);
501 r.CheckNop(kRepBit, kRepWord16);
502 r.CheckNop(kRepBit | kTypeBool, kRepWord16);
503 r.CheckNop(kRepBit, kRepWord32);
504 r.CheckNop(kRepBit | kTypeBool, kRepWord32);
505 r.CheckNop(kRepBit, kRepWord64);
506 r.CheckNop(kRepBit | kTypeBool, kRepWord64);
507}
508
509
510TEST(TypeErrors) {
511 RepresentationChangerTester r;
512
513 // Floats cannot be implicitly converted to/from comparison conditions.
514 r.CheckTypeError(kRepFloat64, kRepBit);
515 r.CheckTypeError(kRepFloat64, kRepBit | kTypeBool);
516 r.CheckTypeError(kRepBit, kRepFloat64);
517 r.CheckTypeError(kRepBit | kTypeBool, kRepFloat64);
518
519 // Floats cannot be implicitly converted to/from comparison conditions.
520 r.CheckTypeError(kRepFloat32, kRepBit);
521 r.CheckTypeError(kRepFloat32, kRepBit | kTypeBool);
522 r.CheckTypeError(kRepBit, kRepFloat32);
523 r.CheckTypeError(kRepBit | kTypeBool, kRepFloat32);
524
525 // Word64 is internal and shouldn't be implicitly converted.
526 r.CheckTypeError(kRepWord64, kRepTagged | kTypeBool);
527 r.CheckTypeError(kRepWord64, kRepTagged);
528 r.CheckTypeError(kRepWord64, kRepTagged | kTypeBool);
529 r.CheckTypeError(kRepTagged, kRepWord64);
530 r.CheckTypeError(kRepTagged | kTypeBool, kRepWord64);
531
532 // Word64 / Word32 shouldn't be implicitly converted.
533 r.CheckTypeError(kRepWord64, kRepWord32);
534 r.CheckTypeError(kRepWord32, kRepWord64);
535 r.CheckTypeError(kRepWord64, kRepWord32 | kTypeInt32);
536 r.CheckTypeError(kRepWord32 | kTypeInt32, kRepWord64);
537 r.CheckTypeError(kRepWord64, kRepWord32 | kTypeUint32);
538 r.CheckTypeError(kRepWord32 | kTypeUint32, kRepWord64);
539
540 for (size_t i = 0; i < arraysize(all_reps); i++) {
541 for (size_t j = 0; j < arraysize(all_reps); j++) {
542 if (i == j) continue;
543 // Only a single from representation is allowed.
544 r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged);
545 }
546 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547}