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 <limits>
6
7 #include "src/ast/scopes.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/change-lowering.h"
10 #include "src/compiler/control-builders.h"
11 #include "src/compiler/graph-reducer.h"
12 #include "src/compiler/graph-visualizer.h"
13 #include "src/compiler/node-properties.h"
14 #include "src/compiler/pipeline.h"
15 #include "src/compiler/representation-change.h"
16 #include "src/compiler/simplified-lowering.h"
17 #include "src/compiler/source-position.h"
18 #include "src/compiler/typer.h"
19 #include "src/compiler/verifier.h"
20 #include "src/execution.h"
21 #include "src/parsing/parser.h"
22 #include "src/parsing/rewriter.h"
23 #include "test/cctest/cctest.h"
24 #include "test/cctest/compiler/codegen-tester.h"
25 #include "test/cctest/compiler/function-tester.h"
26 #include "test/cctest/compiler/graph-builder-tester.h"
27 #include "test/cctest/compiler/value-helper.h"
28
29 namespace v8 {
30 namespace internal {
31 namespace compiler {
32
33 template <typename ReturnType>
34 class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> {
35 public:
SimplifiedLoweringTester(MachineType p0=MachineType::None (),MachineType p1=MachineType::None ())36 SimplifiedLoweringTester(MachineType p0 = MachineType::None(),
37 MachineType p1 = MachineType::None())
38 : GraphBuilderTester<ReturnType>(p0, p1),
39 typer(this->isolate(), this->graph()),
40 javascript(this->zone()),
41 jsgraph(this->isolate(), this->graph(), this->common(), &javascript,
42 this->simplified(), this->machine()),
43 source_positions(jsgraph.graph()),
44 lowering(&jsgraph, this->zone(), &source_positions) {}
45
46 Typer typer;
47 JSOperatorBuilder javascript;
48 JSGraph jsgraph;
49 SourcePositionTable source_positions;
50 SimplifiedLowering lowering;
51
LowerAllNodes()52 void LowerAllNodes() {
53 this->End();
54 typer.Run();
55 lowering.LowerAllNodes();
56 }
57
LowerAllNodesAndLowerChanges()58 void LowerAllNodesAndLowerChanges() {
59 this->End();
60 typer.Run();
61 lowering.LowerAllNodes();
62
63 ChangeLowering lowering(&jsgraph);
64 GraphReducer reducer(this->zone(), this->graph());
65 reducer.AddReducer(&lowering);
66 reducer.ReduceGraph();
67 Verifier::Run(this->graph());
68 }
69
CheckNumberCall(double expected,double input)70 void CheckNumberCall(double expected, double input) {
71 // TODO(titzer): make calls to NewNumber work in cctests.
72 if (expected <= Smi::kMinValue) return;
73 if (expected >= Smi::kMaxValue) return;
74 Handle<Object> num = factory()->NewNumber(input);
75 Object* result = this->Call(*num);
76 CHECK(factory()->NewNumber(expected)->SameValue(result));
77 }
78
79 template <typename T>
CallWithPotentialGC()80 T* CallWithPotentialGC() {
81 // TODO(titzer): we wrap the code in a JSFunction here to reuse the
82 // JSEntryStub; that could be done with a special prologue or other stub.
83 Handle<JSFunction> fun = FunctionTester::ForMachineGraph(this->graph(), 0);
84 Handle<Object>* args = NULL;
85 MaybeHandle<Object> result = Execution::Call(
86 this->isolate(), fun, factory()->undefined_value(), 0, args);
87 return T::cast(*result.ToHandleChecked());
88 }
89
factory()90 Factory* factory() { return this->isolate()->factory(); }
heap()91 Heap* heap() { return this->isolate()->heap(); }
92 };
93
94
95 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
96 // TODO(titzer): test tagged representation for input to NumberToInt32.
TEST(RunNumberToInt32_float64)97 TEST(RunNumberToInt32_float64) {
98 // TODO(titzer): explicit load/stores here are only because of representations
99 double input;
100 int32_t result;
101 SimplifiedLoweringTester<Object*> t;
102 FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
103 MachineType::Float64()};
104 Node* loaded = t.LoadField(load, t.PointerConstant(&input));
105 NodeProperties::SetType(loaded, Type::Number());
106 Node* convert = t.NumberToInt32(loaded);
107 FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
108 MachineType::Int32()};
109 t.StoreField(store, t.PointerConstant(&result), convert);
110 t.Return(t.jsgraph.TrueConstant());
111 t.LowerAllNodesAndLowerChanges();
112 t.GenerateCode();
113
114 FOR_FLOAT64_INPUTS(i) {
115 input = *i;
116 int32_t expected = DoubleToInt32(*i);
117 t.Call();
118 CHECK_EQ(expected, result);
119 }
120 }
121
122
123 // TODO(titzer): test tagged representation for input to NumberToUint32.
TEST(RunNumberToUint32_float64)124 TEST(RunNumberToUint32_float64) {
125 // TODO(titzer): explicit load/stores here are only because of representations
126 double input;
127 uint32_t result;
128 SimplifiedLoweringTester<Object*> t;
129 FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
130 MachineType::Float64()};
131 Node* loaded = t.LoadField(load, t.PointerConstant(&input));
132 NodeProperties::SetType(loaded, Type::Number());
133 Node* convert = t.NumberToUint32(loaded);
134 FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
135 MachineType::Uint32()};
136 t.StoreField(store, t.PointerConstant(&result), convert);
137 t.Return(t.jsgraph.TrueConstant());
138 t.LowerAllNodesAndLowerChanges();
139 t.GenerateCode();
140
141 FOR_FLOAT64_INPUTS(i) {
142 input = *i;
143 uint32_t expected = DoubleToUint32(*i);
144 t.Call();
145 CHECK_EQ(static_cast<int32_t>(expected), static_cast<int32_t>(result));
146 }
147 }
148
149
150 // Create a simple JSObject with a unique map.
TestObject()151 static Handle<JSObject> TestObject() {
152 static int index = 0;
153 char buffer[50];
154 v8::base::OS::SNPrintF(buffer, 50, "({'a_%d':1})", index++);
155 return Handle<JSObject>::cast(v8::Utils::OpenHandle(*CompileRun(buffer)));
156 }
157
158
TEST(RunLoadMap)159 TEST(RunLoadMap) {
160 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
161 FieldAccess access = AccessBuilder::ForMap();
162 Node* load = t.LoadField(access, t.Parameter(0));
163 t.Return(load);
164
165 t.LowerAllNodesAndLowerChanges();
166 t.GenerateCode();
167
168 Handle<JSObject> src = TestObject();
169 Handle<Map> src_map(src->map());
170 Object* result = t.Call(*src); // TODO(titzer): raw pointers in call
171 CHECK_EQ(*src_map, result);
172 }
173
174
TEST(RunStoreMap)175 TEST(RunStoreMap) {
176 SimplifiedLoweringTester<int32_t> t(MachineType::AnyTagged(),
177 MachineType::AnyTagged());
178 FieldAccess access = AccessBuilder::ForMap();
179 t.StoreField(access, t.Parameter(1), t.Parameter(0));
180 t.Return(t.jsgraph.TrueConstant());
181
182 t.LowerAllNodesAndLowerChanges();
183 t.GenerateCode();
184
185 Handle<JSObject> src = TestObject();
186 Handle<Map> src_map(src->map());
187 Handle<JSObject> dst = TestObject();
188 CHECK(src->map() != dst->map());
189 t.Call(*src_map, *dst); // TODO(titzer): raw pointers in call
190 CHECK(*src_map == dst->map());
191 }
192
193
TEST(RunLoadProperties)194 TEST(RunLoadProperties) {
195 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
196 FieldAccess access = AccessBuilder::ForJSObjectProperties();
197 Node* load = t.LoadField(access, t.Parameter(0));
198 t.Return(load);
199
200 t.LowerAllNodesAndLowerChanges();
201 t.GenerateCode();
202
203 Handle<JSObject> src = TestObject();
204 Handle<FixedArray> src_props(src->properties());
205 Object* result = t.Call(*src); // TODO(titzer): raw pointers in call
206 CHECK_EQ(*src_props, result);
207 }
208
209
TEST(RunLoadStoreMap)210 TEST(RunLoadStoreMap) {
211 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged(),
212 MachineType::AnyTagged());
213 FieldAccess access = AccessBuilder::ForMap();
214 Node* load = t.LoadField(access, t.Parameter(0));
215 t.StoreField(access, t.Parameter(1), load);
216 t.Return(load);
217
218 t.LowerAllNodesAndLowerChanges();
219 t.GenerateCode();
220
221 Handle<JSObject> src = TestObject();
222 Handle<Map> src_map(src->map());
223 Handle<JSObject> dst = TestObject();
224 CHECK(src->map() != dst->map());
225 Object* result = t.Call(*src, *dst); // TODO(titzer): raw pointers in call
226 CHECK(result->IsMap());
227 CHECK_EQ(*src_map, result);
228 CHECK(*src_map == dst->map());
229 }
230
231
TEST(RunLoadStoreFixedArrayIndex)232 TEST(RunLoadStoreFixedArrayIndex) {
233 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
234 ElementAccess access = AccessBuilder::ForFixedArrayElement();
235 Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
236 t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
237 t.Return(load);
238
239 t.LowerAllNodesAndLowerChanges();
240 t.GenerateCode();
241
242 Handle<FixedArray> array = t.factory()->NewFixedArray(2);
243 Handle<JSObject> src = TestObject();
244 Handle<JSObject> dst = TestObject();
245 array->set(0, *src);
246 array->set(1, *dst);
247 Object* result = t.Call(*array);
248 CHECK_EQ(*src, result);
249 CHECK_EQ(*src, array->get(0));
250 CHECK_EQ(*src, array->get(1));
251 }
252
253
TEST(RunLoadStoreArrayBuffer)254 TEST(RunLoadStoreArrayBuffer) {
255 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
256 const int index = 12;
257 const int array_length = 2 * index;
258 ElementAccess buffer_access =
259 AccessBuilder::ForTypedArrayElement(kExternalInt8Array, true);
260 Node* backing_store = t.LoadField(
261 AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
262 Node* load =
263 t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
264 t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
265 load);
266 t.Return(t.jsgraph.TrueConstant());
267
268 t.LowerAllNodesAndLowerChanges();
269 t.GenerateCode();
270
271 Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer();
272 JSArrayBuffer::SetupAllocatingData(array, t.isolate(), array_length);
273 uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store());
274 for (int i = 0; i < array_length; i++) {
275 data[i] = i;
276 }
277
278 // TODO(titzer): raw pointers in call
279 Object* result = t.Call(*array);
280 CHECK_EQ(t.isolate()->heap()->true_value(), result);
281 for (int i = 0; i < array_length; i++) {
282 uint8_t expected = i;
283 if (i == (index + 1)) expected = index;
284 CHECK_EQ(data[i], expected);
285 }
286 }
287
288
TEST(RunLoadFieldFromUntaggedBase)289 TEST(RunLoadFieldFromUntaggedBase) {
290 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
291
292 for (size_t i = 0; i < arraysize(smis); i++) {
293 int offset = static_cast<int>(i * sizeof(Smi*));
294 FieldAccess access = {kUntaggedBase, offset, Handle<Name>(),
295 Type::Integral32(), MachineType::AnyTagged()};
296
297 SimplifiedLoweringTester<Object*> t;
298 Node* load = t.LoadField(access, t.PointerConstant(smis));
299 t.Return(load);
300 t.LowerAllNodesAndLowerChanges();
301
302 for (int j = -5; j <= 5; j++) {
303 Smi* expected = Smi::FromInt(j);
304 smis[i] = expected;
305 CHECK_EQ(expected, t.Call());
306 }
307 }
308 }
309
310
TEST(RunStoreFieldToUntaggedBase)311 TEST(RunStoreFieldToUntaggedBase) {
312 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
313
314 for (size_t i = 0; i < arraysize(smis); i++) {
315 int offset = static_cast<int>(i * sizeof(Smi*));
316 FieldAccess access = {kUntaggedBase, offset, Handle<Name>(),
317 Type::Integral32(), MachineType::AnyTagged()};
318
319 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
320 Node* p0 = t.Parameter(0);
321 t.StoreField(access, t.PointerConstant(smis), p0);
322 t.Return(p0);
323 t.LowerAllNodesAndLowerChanges();
324
325 for (int j = -5; j <= 5; j++) {
326 Smi* expected = Smi::FromInt(j);
327 smis[i] = Smi::FromInt(-100);
328 CHECK_EQ(expected, t.Call(expected));
329 CHECK_EQ(expected, smis[i]);
330 }
331 }
332 }
333
334
TEST(RunLoadElementFromUntaggedBase)335 TEST(RunLoadElementFromUntaggedBase) {
336 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
337 Smi::FromInt(4), Smi::FromInt(5)};
338
339 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes
340 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index
341 int offset = static_cast<int>(i * sizeof(Smi*));
342 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
343 MachineType::AnyTagged()};
344
345 SimplifiedLoweringTester<Object*> t;
346 Node* load = t.LoadElement(access, t.PointerConstant(smis),
347 t.Int32Constant(static_cast<int>(j)));
348 t.Return(load);
349 t.LowerAllNodesAndLowerChanges();
350
351 for (int k = -5; k <= 5; k++) {
352 Smi* expected = Smi::FromInt(k);
353 smis[i + j] = expected;
354 CHECK_EQ(expected, t.Call());
355 }
356 }
357 }
358 }
359
360
TEST(RunStoreElementFromUntaggedBase)361 TEST(RunStoreElementFromUntaggedBase) {
362 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
363 Smi::FromInt(4), Smi::FromInt(5)};
364
365 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes
366 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index
367 int offset = static_cast<int>(i * sizeof(Smi*));
368 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
369 MachineType::AnyTagged()};
370
371 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
372 Node* p0 = t.Parameter(0);
373 t.StoreElement(access, t.PointerConstant(smis),
374 t.Int32Constant(static_cast<int>(j)), p0);
375 t.Return(p0);
376 t.LowerAllNodesAndLowerChanges();
377
378 for (int k = -5; k <= 5; k++) {
379 Smi* expected = Smi::FromInt(k);
380 smis[i + j] = Smi::FromInt(-100);
381 CHECK_EQ(expected, t.Call(expected));
382 CHECK_EQ(expected, smis[i + j]);
383 }
384
385 // TODO(titzer): assert the contents of the array.
386 }
387 }
388 }
389
390
391 // A helper class for accessing fields and elements of various types, on both
392 // tagged and untagged base pointers. Contains both tagged and untagged buffers
393 // for testing direct memory access from generated code.
394 template <typename E>
395 class AccessTester : public HandleAndZoneScope {
396 public:
397 bool tagged;
398 MachineType rep;
399 E* original_elements;
400 size_t num_elements;
401 E* untagged_array;
402 Handle<ByteArray> tagged_array; // TODO(titzer): use FixedArray for tagged.
403
AccessTester(bool t,MachineType r,E * orig,size_t num)404 AccessTester(bool t, MachineType r, E* orig, size_t num)
405 : tagged(t),
406 rep(r),
407 original_elements(orig),
408 num_elements(num),
409 untagged_array(static_cast<E*>(malloc(ByteSize()))),
410 tagged_array(main_isolate()->factory()->NewByteArray(
411 static_cast<int>(ByteSize()))) {
412 Reinitialize();
413 }
414
~AccessTester()415 ~AccessTester() { free(untagged_array); }
416
ByteSize()417 size_t ByteSize() { return num_elements * sizeof(E); }
418
419 // Nuke both {untagged_array} and {tagged_array} with {original_elements}.
Reinitialize()420 void Reinitialize() {
421 memcpy(untagged_array, original_elements, ByteSize());
422 CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length());
423 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress());
424 memcpy(raw, original_elements, ByteSize());
425 }
426
427 // Create and run code that copies the element in either {untagged_array}
428 // or {tagged_array} at index {from_index} to index {to_index}.
RunCopyElement(int from_index,int to_index)429 void RunCopyElement(int from_index, int to_index) {
430 // TODO(titzer): test element and field accesses where the base is not
431 // a constant in the code.
432 BoundsCheck(from_index);
433 BoundsCheck(to_index);
434 ElementAccess access = GetElementAccess();
435
436 SimplifiedLoweringTester<Object*> t;
437 Node* ptr = GetBaseNode(&t);
438 Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
439 t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
440 t.Return(t.jsgraph.TrueConstant());
441 t.LowerAllNodesAndLowerChanges();
442 t.GenerateCode();
443
444 Object* result = t.Call();
445 CHECK_EQ(t.isolate()->heap()->true_value(), result);
446 }
447
448 // Create and run code that copies the field in either {untagged_array}
449 // or {tagged_array} at index {from_index} to index {to_index}.
RunCopyField(int from_index,int to_index)450 void RunCopyField(int from_index, int to_index) {
451 BoundsCheck(from_index);
452 BoundsCheck(to_index);
453 FieldAccess from_access = GetFieldAccess(from_index);
454 FieldAccess to_access = GetFieldAccess(to_index);
455
456 SimplifiedLoweringTester<Object*> t;
457 Node* ptr = GetBaseNode(&t);
458 Node* load = t.LoadField(from_access, ptr);
459 t.StoreField(to_access, ptr, load);
460 t.Return(t.jsgraph.TrueConstant());
461 t.LowerAllNodesAndLowerChanges();
462 t.GenerateCode();
463
464 Object* result = t.Call();
465 CHECK_EQ(t.isolate()->heap()->true_value(), result);
466 }
467
468 // Create and run code that copies the elements from {this} to {that}.
RunCopyElements(AccessTester<E> * that)469 void RunCopyElements(AccessTester<E>* that) {
470 // TODO(titzer): Rewrite this test without StructuredGraphBuilder support.
471 #if 0
472 SimplifiedLoweringTester<Object*> t;
473
474 Node* one = t.Int32Constant(1);
475 Node* index = t.Int32Constant(0);
476 Node* limit = t.Int32Constant(static_cast<int>(num_elements));
477 t.environment()->Push(index);
478 Node* src = this->GetBaseNode(&t);
479 Node* dst = that->GetBaseNode(&t);
480 {
481 LoopBuilder loop(&t);
482 loop.BeginLoop();
483 // Loop exit condition
484 index = t.environment()->Top();
485 Node* condition = t.Int32LessThan(index, limit);
486 loop.BreakUnless(condition);
487 // dst[index] = src[index]
488 index = t.environment()->Pop();
489 Node* load = t.LoadElement(this->GetElementAccess(), src, index);
490 t.StoreElement(that->GetElementAccess(), dst, index, load);
491 // index++
492 index = t.Int32Add(index, one);
493 t.environment()->Push(index);
494 // continue
495 loop.EndBody();
496 loop.EndLoop();
497 }
498 index = t.environment()->Pop();
499 t.Return(t.jsgraph.TrueConstant());
500 t.LowerAllNodes();
501 t.GenerateCode();
502
503 Object* result = t.Call();
504 CHECK_EQ(t.isolate()->heap()->true_value(), result);
505 #endif
506 }
507
GetElement(int index)508 E GetElement(int index) {
509 BoundsCheck(index);
510 if (tagged) {
511 return GetTaggedElement(index);
512 } else {
513 return untagged_array[index];
514 }
515 }
516
517 private:
GetElementAccess()518 ElementAccess GetElementAccess() {
519 ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase,
520 tagged ? FixedArrayBase::kHeaderSize : 0,
521 Type::Any(), rep};
522 return access;
523 }
524
GetFieldAccess(int field)525 FieldAccess GetFieldAccess(int field) {
526 int offset = field * sizeof(E);
527 FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase,
528 offset + (tagged ? FixedArrayBase::kHeaderSize : 0),
529 Handle<Name>(), Type::Any(), rep};
530 return access;
531 }
532
533 template <typename T>
GetBaseNode(SimplifiedLoweringTester<T> * t)534 Node* GetBaseNode(SimplifiedLoweringTester<T>* t) {
535 return tagged ? t->HeapConstant(tagged_array)
536 : t->PointerConstant(untagged_array);
537 }
538
BoundsCheck(int index)539 void BoundsCheck(int index) {
540 CHECK_GE(index, 0);
541 CHECK_LT(index, static_cast<int>(num_elements));
542 CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length());
543 }
544
GetTaggedElement(int index)545 E GetTaggedElement(int index) {
546 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress());
547 return raw[index];
548 }
549 };
550
551 template <>
GetTaggedElement(int index)552 double AccessTester<double>::GetTaggedElement(int index) {
553 return ReadDoubleValue(tagged_array->GetDataStartAddress() +
554 index * sizeof(double));
555 }
556
557
558 template <typename E>
RunAccessTest(MachineType rep,E * original_elements,size_t num)559 static void RunAccessTest(MachineType rep, E* original_elements, size_t num) {
560 int num_elements = static_cast<int>(num);
561
562 for (int taggedness = 0; taggedness < 2; taggedness++) {
563 AccessTester<E> a(taggedness == 1, rep, original_elements, num);
564 for (int field = 0; field < 2; field++) {
565 for (int i = 0; i < num_elements - 1; i++) {
566 a.Reinitialize();
567 if (field == 0) {
568 a.RunCopyField(i, i + 1); // Test field read/write.
569 } else {
570 a.RunCopyElement(i, i + 1); // Test element read/write.
571 }
572 for (int j = 0; j < num_elements; j++) {
573 E expect =
574 j == (i + 1) ? original_elements[i] : original_elements[j];
575 CHECK_EQ(expect, a.GetElement(j));
576 }
577 }
578 }
579 }
580 // Test array copy.
581 for (int tf = 0; tf < 2; tf++) {
582 for (int tt = 0; tt < 2; tt++) {
583 AccessTester<E> a(tf == 1, rep, original_elements, num);
584 AccessTester<E> b(tt == 1, rep, original_elements, num);
585 a.RunCopyElements(&b);
586 for (int i = 0; i < num_elements; i++) {
587 CHECK_EQ(a.GetElement(i), b.GetElement(i));
588 }
589 }
590 }
591 }
592
593
TEST(RunAccessTests_uint8)594 TEST(RunAccessTests_uint8) {
595 uint8_t data[] = {0x07, 0x16, 0x25, 0x34, 0x43, 0x99,
596 0xab, 0x78, 0x89, 0x19, 0x2b, 0x38};
597 RunAccessTest<uint8_t>(MachineType::Int8(), data, arraysize(data));
598 }
599
600
TEST(RunAccessTests_uint16)601 TEST(RunAccessTests_uint16) {
602 uint16_t data[] = {0x071a, 0x162b, 0x253c, 0x344d, 0x435e, 0x7777};
603 RunAccessTest<uint16_t>(MachineType::Int16(), data, arraysize(data));
604 }
605
606
TEST(RunAccessTests_int32)607 TEST(RunAccessTests_int32) {
608 int32_t data[] = {-211, 211, 628347, 2000000000, -2000000000, -1, -100000034};
609 RunAccessTest<int32_t>(MachineType::Int32(), data, arraysize(data));
610 }
611
612
613 #define V8_2PART_INT64(a, b) (((static_cast<int64_t>(a) << 32) + 0x##b##u))
614
615
TEST(RunAccessTests_int64)616 TEST(RunAccessTests_int64) {
617 if (kPointerSize != 8) return;
618 int64_t data[] = {V8_2PART_INT64(0x10111213, 14151617),
619 V8_2PART_INT64(0x20212223, 24252627),
620 V8_2PART_INT64(0x30313233, 34353637),
621 V8_2PART_INT64(0xa0a1a2a3, a4a5a6a7),
622 V8_2PART_INT64(0xf0f1f2f3, f4f5f6f7)};
623 RunAccessTest<int64_t>(MachineType::Int64(), data, arraysize(data));
624 }
625
626
TEST(RunAccessTests_float64)627 TEST(RunAccessTests_float64) {
628 double data[] = {1.25, -1.25, 2.75, 11.0, 11100.8};
629 RunAccessTest<double>(MachineType::Float64(), data, arraysize(data));
630 }
631
632
TEST(RunAccessTests_Smi)633 TEST(RunAccessTests_Smi) {
634 Smi* data[] = {Smi::FromInt(-1), Smi::FromInt(-9),
635 Smi::FromInt(0), Smi::FromInt(666),
636 Smi::FromInt(77777), Smi::FromInt(Smi::kMaxValue)};
637 RunAccessTest<Smi*>(MachineType::AnyTagged(), data, arraysize(data));
638 }
639
640
TEST(RunAllocate)641 TEST(RunAllocate) {
642 PretenureFlag flag[] = {NOT_TENURED, TENURED};
643
644 for (size_t i = 0; i < arraysize(flag); i++) {
645 SimplifiedLoweringTester<HeapObject*> t;
646 FieldAccess access = AccessBuilder::ForMap();
647 Node* size = t.jsgraph.Constant(HeapNumber::kSize);
648 Node* alloc = t.NewNode(t.simplified()->Allocate(flag[i]), size);
649 Node* map = t.jsgraph.Constant(t.factory()->heap_number_map());
650 t.StoreField(access, alloc, map);
651 t.Return(alloc);
652
653 t.LowerAllNodesAndLowerChanges();
654 t.GenerateCode();
655
656 HeapObject* result = t.CallWithPotentialGC<HeapObject>();
657 CHECK(t.heap()->new_space()->Contains(result) || flag[i] == TENURED);
658 CHECK(t.heap()->old_space()->Contains(result) || flag[i] == NOT_TENURED);
659 CHECK(result->IsHeapNumber());
660 }
661 }
662
663
664 // Fills in most of the nodes of the graph in order to make tests shorter.
665 class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
666 public:
667 Typer typer;
668 JSOperatorBuilder javascript;
669 JSGraph jsgraph;
670 Node* p0;
671 Node* p1;
672 Node* p2;
673 Node* start;
674 Node* end;
675 Node* ret;
676
TestingGraph(Type * p0_type,Type * p1_type=Type::None (),Type * p2_type=Type::None ())677 explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
678 Type* p2_type = Type::None())
679 : GraphAndBuilders(main_zone()),
680 typer(main_isolate(), graph()),
681 javascript(main_zone()),
682 jsgraph(main_isolate(), graph(), common(), &javascript, simplified(),
683 machine()) {
684 start = graph()->NewNode(common()->Start(4));
685 graph()->SetStart(start);
686 ret =
687 graph()->NewNode(common()->Return(), jsgraph.Constant(0), start, start);
688 end = graph()->NewNode(common()->End(1), ret);
689 graph()->SetEnd(end);
690 p0 = graph()->NewNode(common()->Parameter(0), start);
691 p1 = graph()->NewNode(common()->Parameter(1), start);
692 p2 = graph()->NewNode(common()->Parameter(2), start);
693 typer.Run();
694 NodeProperties::SetType(p0, p0_type);
695 NodeProperties::SetType(p1, p1_type);
696 NodeProperties::SetType(p2, p2_type);
697 }
698
CheckLoweringBinop(IrOpcode::Value expected,const Operator * op)699 void CheckLoweringBinop(IrOpcode::Value expected, const Operator* op) {
700 Node* node = Return(graph()->NewNode(op, p0, p1));
701 Lower();
702 CHECK_EQ(expected, node->opcode());
703 }
704
CheckLoweringStringBinop(IrOpcode::Value expected,const Operator * op)705 void CheckLoweringStringBinop(IrOpcode::Value expected, const Operator* op) {
706 Node* node = Return(
707 graph()->NewNode(op, p0, p1, graph()->start(), graph()->start()));
708 Lower();
709 CHECK_EQ(expected, node->opcode());
710 }
711
CheckLoweringTruncatedBinop(IrOpcode::Value expected,const Operator * op,const Operator * trunc)712 void CheckLoweringTruncatedBinop(IrOpcode::Value expected, const Operator* op,
713 const Operator* trunc) {
714 Node* node = graph()->NewNode(op, p0, p1);
715 Return(graph()->NewNode(trunc, node));
716 Lower();
717 CHECK_EQ(expected, node->opcode());
718 }
719
Lower()720 void Lower() {
721 SourcePositionTable table(jsgraph.graph());
722 SimplifiedLowering(&jsgraph, jsgraph.zone(), &table).LowerAllNodes();
723 }
724
LowerAllNodesAndLowerChanges()725 void LowerAllNodesAndLowerChanges() {
726 SourcePositionTable table(jsgraph.graph());
727 SimplifiedLowering(&jsgraph, jsgraph.zone(), &table).LowerAllNodes();
728
729 ChangeLowering lowering(&jsgraph);
730 GraphReducer reducer(this->zone(), this->graph());
731 reducer.AddReducer(&lowering);
732 reducer.ReduceGraph();
733 Verifier::Run(this->graph());
734 }
735
736 // Inserts the node as the return value of the graph.
Return(Node * node)737 Node* Return(Node* node) {
738 ret->ReplaceInput(0, node);
739 return node;
740 }
741
742 // Inserts the node as the effect input to the return of the graph.
Effect(Node * node)743 void Effect(Node* node) { ret->ReplaceInput(1, node); }
744
ExampleWithOutput(MachineType type)745 Node* ExampleWithOutput(MachineType type) {
746 if (type.semantic() == MachineSemantic::kInt32) {
747 return graph()->NewNode(machine()->Int32Add(), jsgraph.Int32Constant(1),
748 jsgraph.Int32Constant(1));
749 } else if (type.semantic() == MachineSemantic::kUint32) {
750 return graph()->NewNode(machine()->Word32Shr(), jsgraph.Int32Constant(1),
751 jsgraph.Int32Constant(1));
752 } else if (type.representation() == MachineRepresentation::kFloat64) {
753 return graph()->NewNode(machine()->Float64Add(),
754 jsgraph.Float64Constant(1),
755 jsgraph.Float64Constant(1));
756 } else if (type.representation() == MachineRepresentation::kBit) {
757 return graph()->NewNode(machine()->Word32Equal(),
758 jsgraph.Int32Constant(1),
759 jsgraph.Int32Constant(1));
760 } else if (type.representation() == MachineRepresentation::kWord64) {
761 return graph()->NewNode(machine()->Int64Add(), Int64Constant(1),
762 Int64Constant(1));
763 } else {
764 CHECK(type.representation() == MachineRepresentation::kTagged);
765 return p0;
766 }
767 }
768
Use(Node * node,MachineType type)769 Node* Use(Node* node, MachineType type) {
770 if (type.semantic() == MachineSemantic::kInt32) {
771 return graph()->NewNode(machine()->Int32LessThan(), node,
772 jsgraph.Int32Constant(1));
773 } else if (type.semantic() == MachineSemantic::kUint32) {
774 return graph()->NewNode(machine()->Uint32LessThan(), node,
775 jsgraph.Int32Constant(1));
776 } else if (type.representation() == MachineRepresentation::kFloat64) {
777 return graph()->NewNode(machine()->Float64Add(), node,
778 jsgraph.Float64Constant(1));
779 } else if (type.representation() == MachineRepresentation::kWord64) {
780 return graph()->NewNode(machine()->Int64LessThan(), node,
781 Int64Constant(1));
782 } else if (type.representation() == MachineRepresentation::kWord32) {
783 return graph()->NewNode(machine()->Word32Equal(), node,
784 jsgraph.Int32Constant(1));
785 } else {
786 return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
787 jsgraph.TrueConstant());
788 }
789 }
790
Branch(Node * cond)791 Node* Branch(Node* cond) {
792 Node* br = graph()->NewNode(common()->Branch(), cond, start);
793 Node* tb = graph()->NewNode(common()->IfTrue(), br);
794 Node* fb = graph()->NewNode(common()->IfFalse(), br);
795 Node* m = graph()->NewNode(common()->Merge(2), tb, fb);
796 NodeProperties::ReplaceControlInput(ret, m);
797 return br;
798 }
799
Int64Constant(int64_t v)800 Node* Int64Constant(int64_t v) {
801 return graph()->NewNode(common()->Int64Constant(v));
802 }
803
simplified()804 SimplifiedOperatorBuilder* simplified() { return &main_simplified_; }
machine()805 MachineOperatorBuilder* machine() { return &main_machine_; }
common()806 CommonOperatorBuilder* common() { return &main_common_; }
graph()807 Graph* graph() { return main_graph_; }
808 };
809
810
TEST(LowerBooleanNot_bit_bit)811 TEST(LowerBooleanNot_bit_bit) {
812 // BooleanNot(x: kRepBit) used as kRepBit
813 TestingGraph t(Type::Boolean());
814 Node* b = t.ExampleWithOutput(MachineType::Bool());
815 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
816 Node* use = t.Branch(inv);
817 t.Lower();
818 Node* cmp = use->InputAt(0);
819 CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
820 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
821 Node* f = t.jsgraph.Int32Constant(0);
822 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
823 }
824
825
TEST(LowerBooleanNot_bit_tagged)826 TEST(LowerBooleanNot_bit_tagged) {
827 // BooleanNot(x: kRepBit) used as kRepTagged
828 TestingGraph t(Type::Boolean());
829 Node* b = t.ExampleWithOutput(MachineType::Bool());
830 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
831 Node* use = t.Use(inv, MachineType::AnyTagged());
832 t.Return(use);
833 t.Lower();
834 CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
835 Node* cmp = use->InputAt(0)->InputAt(0);
836 CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
837 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
838 Node* f = t.jsgraph.Int32Constant(0);
839 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
840 }
841
842
TEST(LowerBooleanNot_tagged_bit)843 TEST(LowerBooleanNot_tagged_bit) {
844 // BooleanNot(x: kRepTagged) used as kRepBit
845 TestingGraph t(Type::Boolean());
846 Node* b = t.p0;
847 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
848 Node* use = t.Branch(inv);
849 t.Lower();
850 Node* cmp = use->InputAt(0);
851 CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
852 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
853 Node* f = t.jsgraph.FalseConstant();
854 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
855 }
856
857
TEST(LowerBooleanNot_tagged_tagged)858 TEST(LowerBooleanNot_tagged_tagged) {
859 // BooleanNot(x: kRepTagged) used as kRepTagged
860 TestingGraph t(Type::Boolean());
861 Node* b = t.p0;
862 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
863 Node* use = t.Use(inv, MachineType::AnyTagged());
864 t.Return(use);
865 t.Lower();
866 CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
867 Node* cmp = use->InputAt(0)->InputAt(0);
868 CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
869 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
870 Node* f = t.jsgraph.FalseConstant();
871 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
872 }
873
874
TEST(LowerBooleanToNumber_bit_int32)875 TEST(LowerBooleanToNumber_bit_int32) {
876 // BooleanToNumber(x: kRepBit) used as MachineType::Int32()
877 TestingGraph t(Type::Boolean());
878 Node* b = t.ExampleWithOutput(MachineType::Bool());
879 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
880 Node* use = t.Use(cnv, MachineType::Int32());
881 t.Return(use);
882 t.Lower();
883 CHECK_EQ(b, use->InputAt(0));
884 }
885
886
TEST(LowerBooleanToNumber_tagged_int32)887 TEST(LowerBooleanToNumber_tagged_int32) {
888 // BooleanToNumber(x: kRepTagged) used as MachineType::Int32()
889 TestingGraph t(Type::Boolean());
890 Node* b = t.p0;
891 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
892 Node* use = t.Use(cnv, MachineType::Int32());
893 t.Return(use);
894 t.Lower();
895 CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
896 CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
897 Node* c = t.jsgraph.TrueConstant();
898 CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
899 }
900
901
TEST(LowerBooleanToNumber_bit_tagged)902 TEST(LowerBooleanToNumber_bit_tagged) {
903 // BooleanToNumber(x: kRepBit) used as MachineType::AnyTagged()
904 TestingGraph t(Type::Boolean());
905 Node* b = t.ExampleWithOutput(MachineType::Bool());
906 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
907 Node* use = t.Use(cnv, MachineType::AnyTagged());
908 t.Return(use);
909 t.Lower();
910 CHECK_EQ(b, use->InputAt(0)->InputAt(0));
911 CHECK_EQ(IrOpcode::kChangeUint32ToTagged, use->InputAt(0)->opcode());
912 }
913
914
TEST(LowerBooleanToNumber_tagged_tagged)915 TEST(LowerBooleanToNumber_tagged_tagged) {
916 // BooleanToNumber(x: kRepTagged) used as MachineType::AnyTagged()
917 TestingGraph t(Type::Boolean());
918 Node* b = t.p0;
919 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
920 Node* use = t.Use(cnv, MachineType::AnyTagged());
921 t.Return(use);
922 t.Lower();
923 CHECK_EQ(cnv, use->InputAt(0)->InputAt(0));
924 CHECK_EQ(IrOpcode::kChangeUint32ToTagged, use->InputAt(0)->opcode());
925 CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
926 CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
927 Node* c = t.jsgraph.TrueConstant();
928 CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
929 }
930
931
932 static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(),
933 Type::Number(), Type::Any()};
934
935
TEST(LowerNumberCmp_to_int32)936 TEST(LowerNumberCmp_to_int32) {
937 TestingGraph t(Type::Signed32(), Type::Signed32());
938
939 t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual());
940 t.CheckLoweringBinop(IrOpcode::kInt32LessThan,
941 t.simplified()->NumberLessThan());
942 t.CheckLoweringBinop(IrOpcode::kInt32LessThanOrEqual,
943 t.simplified()->NumberLessThanOrEqual());
944 }
945
946
TEST(LowerNumberCmp_to_uint32)947 TEST(LowerNumberCmp_to_uint32) {
948 TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
949
950 t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual());
951 t.CheckLoweringBinop(IrOpcode::kUint32LessThan,
952 t.simplified()->NumberLessThan());
953 t.CheckLoweringBinop(IrOpcode::kUint32LessThanOrEqual,
954 t.simplified()->NumberLessThanOrEqual());
955 }
956
957
TEST(LowerNumberCmp_to_float64)958 TEST(LowerNumberCmp_to_float64) {
959 static Type* types[] = {Type::Number(), Type::Any()};
960
961 for (size_t i = 0; i < arraysize(types); i++) {
962 TestingGraph t(types[i], types[i]);
963
964 t.CheckLoweringBinop(IrOpcode::kFloat64Equal,
965 t.simplified()->NumberEqual());
966 t.CheckLoweringBinop(IrOpcode::kFloat64LessThan,
967 t.simplified()->NumberLessThan());
968 t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual,
969 t.simplified()->NumberLessThanOrEqual());
970 }
971 }
972
973
TEST(LowerNumberAddSub_to_int32)974 TEST(LowerNumberAddSub_to_int32) {
975 HandleAndZoneScope scope;
976 Type* small_range = Type::Range(1, 10, scope.main_zone());
977 Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone());
978 static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
979 large_range};
980
981 for (size_t i = 0; i < arraysize(types); i++) {
982 for (size_t j = 0; j < arraysize(types); j++) {
983 TestingGraph t(types[i], types[j]);
984 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
985 t.simplified()->NumberAdd(),
986 t.simplified()->NumberToInt32());
987 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
988 t.simplified()->NumberSubtract(),
989 t.simplified()->NumberToInt32());
990 }
991 }
992 }
993
994
TEST(LowerNumberAddSub_to_uint32)995 TEST(LowerNumberAddSub_to_uint32) {
996 HandleAndZoneScope scope;
997 Type* small_range = Type::Range(1, 10, scope.main_zone());
998 Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone());
999 static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
1000 large_range};
1001
1002 for (size_t i = 0; i < arraysize(types); i++) {
1003 for (size_t j = 0; j < arraysize(types); j++) {
1004 TestingGraph t(types[i], types[j]);
1005 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
1006 t.simplified()->NumberAdd(),
1007 t.simplified()->NumberToUint32());
1008 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
1009 t.simplified()->NumberSubtract(),
1010 t.simplified()->NumberToUint32());
1011 }
1012 }
1013 }
1014
1015
TEST(LowerNumberAddSub_to_float64)1016 TEST(LowerNumberAddSub_to_float64) {
1017 for (size_t i = 0; i < arraysize(test_types); i++) {
1018 TestingGraph t(test_types[i], test_types[i]);
1019
1020 t.CheckLoweringBinop(IrOpcode::kFloat64Add, t.simplified()->NumberAdd());
1021 t.CheckLoweringBinop(IrOpcode::kFloat64Sub,
1022 t.simplified()->NumberSubtract());
1023 }
1024 }
1025
1026
TEST(LowerNumberDivMod_to_float64)1027 TEST(LowerNumberDivMod_to_float64) {
1028 for (size_t i = 0; i < arraysize(test_types); i++) {
1029 TestingGraph t(test_types[i], test_types[i]);
1030
1031 t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
1032 if (!test_types[i]->Is(Type::Unsigned32())) {
1033 t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
1034 t.simplified()->NumberModulus());
1035 }
1036 }
1037 }
1038
1039
CheckChangeOf(IrOpcode::Value change,Node * of,Node * node)1040 static void CheckChangeOf(IrOpcode::Value change, Node* of, Node* node) {
1041 CHECK_EQ(change, node->opcode());
1042 CHECK_EQ(of, node->InputAt(0));
1043 }
1044
1045
TEST(LowerNumberToInt32_to_ChangeTaggedToInt32)1046 TEST(LowerNumberToInt32_to_ChangeTaggedToInt32) {
1047 // NumberToInt32(x: kRepTagged | kTypeInt32) used as kRepWord32
1048 TestingGraph t(Type::Signed32());
1049 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
1050 Node* use = t.Use(trunc, MachineType::Int32());
1051 t.Return(use);
1052 t.Lower();
1053 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p0, use->InputAt(0));
1054 }
1055
1056
TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32)1057 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
1058 // NumberToInt32(x: kRepFloat64) used as MachineType::Int32()
1059 TestingGraph t(Type::Number());
1060 Node* p0 = t.ExampleWithOutput(MachineType::Float64());
1061 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
1062 Node* use = t.Use(trunc, MachineType::Int32());
1063 t.Return(use);
1064 t.Lower();
1065 CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, p0, use->InputAt(0));
1066 }
1067
1068
TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32_with_change)1069 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32_with_change) {
1070 // NumberToInt32(x: kTypeNumber | kRepTagged) used as MachineType::Int32()
1071 TestingGraph t(Type::Number());
1072 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
1073 Node* use = t.Use(trunc, MachineType::Int32());
1074 t.Return(use);
1075 t.Lower();
1076 Node* node = use->InputAt(0);
1077 CHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, node->opcode());
1078 Node* of = node->InputAt(0);
1079 CHECK_EQ(IrOpcode::kChangeTaggedToFloat64, of->opcode());
1080 CHECK_EQ(t.p0, of->InputAt(0));
1081 }
1082
1083
TEST(LowerNumberToUint32_to_ChangeTaggedToUint32)1084 TEST(LowerNumberToUint32_to_ChangeTaggedToUint32) {
1085 // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepWord32
1086 TestingGraph t(Type::Unsigned32());
1087 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
1088 Node* use = t.Use(trunc, MachineType::Uint32());
1089 t.Return(use);
1090 t.Lower();
1091 CheckChangeOf(IrOpcode::kChangeTaggedToUint32, t.p0, use->InputAt(0));
1092 }
1093
1094
TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32)1095 TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32) {
1096 // NumberToUint32(x: kRepFloat64) used as MachineType::Uint32()
1097 TestingGraph t(Type::Number());
1098 Node* p0 = t.ExampleWithOutput(MachineType::Float64());
1099 // TODO(titzer): run the typer here, or attach machine type to param.
1100 NodeProperties::SetType(p0, Type::Number());
1101 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
1102 Node* use = t.Use(trunc, MachineType::Uint32());
1103 t.Return(use);
1104 t.Lower();
1105 CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, p0, use->InputAt(0));
1106 }
1107
1108
TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_with_change)1109 TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_with_change) {
1110 // NumberToInt32(x: kTypeNumber | kRepTagged) used as MachineType::Uint32()
1111 TestingGraph t(Type::Number());
1112 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
1113 Node* use = t.Use(trunc, MachineType::Uint32());
1114 t.Return(use);
1115 t.Lower();
1116 Node* node = use->InputAt(0);
1117 CHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, node->opcode());
1118 Node* of = node->InputAt(0);
1119 CHECK_EQ(IrOpcode::kChangeTaggedToFloat64, of->opcode());
1120 CHECK_EQ(t.p0, of->InputAt(0));
1121 }
1122
1123
TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32)1124 TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32) {
1125 // NumberToUint32(x: kRepFloat64) used as kRepWord32
1126 TestingGraph t(Type::Unsigned32());
1127 Node* input = t.ExampleWithOutput(MachineType::Float64());
1128 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input);
1129 Node* use = t.Use(trunc, MachineType::RepWord32());
1130 t.Return(use);
1131 t.Lower();
1132 CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, input, use->InputAt(0));
1133 }
1134
1135
TEST(LowerReferenceEqual_to_wordeq)1136 TEST(LowerReferenceEqual_to_wordeq) {
1137 TestingGraph t(Type::Any(), Type::Any());
1138 IrOpcode::Value opcode =
1139 static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode());
1140 t.CheckLoweringBinop(opcode, t.simplified()->ReferenceEqual(Type::Any()));
1141 }
1142
1143
TEST(LowerStringOps_to_call_and_compare)1144 TEST(LowerStringOps_to_call_and_compare) {
1145 // These tests need linkage for the calls.
1146 TestingGraph t(Type::String(), Type::String());
1147 IrOpcode::Value compare_eq =
1148 static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode());
1149 IrOpcode::Value compare_lt =
1150 static_cast<IrOpcode::Value>(t.machine()->IntLessThan()->opcode());
1151 IrOpcode::Value compare_le = static_cast<IrOpcode::Value>(
1152 t.machine()->IntLessThanOrEqual()->opcode());
1153 t.CheckLoweringStringBinop(compare_eq, t.simplified()->StringEqual());
1154 t.CheckLoweringStringBinop(compare_lt, t.simplified()->StringLessThan());
1155 t.CheckLoweringStringBinop(compare_le,
1156 t.simplified()->StringLessThanOrEqual());
1157 }
1158
1159
CheckChangeInsertion(IrOpcode::Value expected,MachineType from,MachineType to,Type * type=Type::Any ())1160 void CheckChangeInsertion(IrOpcode::Value expected, MachineType from,
1161 MachineType to, Type* type = Type::Any()) {
1162 TestingGraph t(Type::Any());
1163 Node* in = t.ExampleWithOutput(from);
1164 NodeProperties::SetType(in, type);
1165 Node* use = t.Use(in, to);
1166 t.Return(use);
1167 t.Lower();
1168 CHECK_EQ(expected, use->InputAt(0)->opcode());
1169 CHECK_EQ(in, use->InputAt(0)->InputAt(0));
1170 }
1171
1172
TEST(InsertBasicChanges)1173 TEST(InsertBasicChanges) {
1174 CheckChangeInsertion(IrOpcode::kChangeFloat64ToInt32, MachineType::Float64(),
1175 MachineType::Int32(), Type::Signed32());
1176 CheckChangeInsertion(IrOpcode::kChangeFloat64ToUint32, MachineType::Float64(),
1177 MachineType::Uint32(), Type::Unsigned32());
1178 CheckChangeInsertion(IrOpcode::kTruncateFloat64ToInt32,
1179 MachineType::Float64(), MachineType::Uint32(),
1180 Type::Integral32());
1181 CheckChangeInsertion(IrOpcode::kChangeTaggedToInt32, MachineType::AnyTagged(),
1182 MachineType::Int32(), Type::Signed32());
1183 CheckChangeInsertion(IrOpcode::kChangeTaggedToUint32,
1184 MachineType::AnyTagged(), MachineType::Uint32(),
1185 Type::Unsigned32());
1186
1187 CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, MachineType::Float64(),
1188 MachineType::AnyTagged());
1189 CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64,
1190 MachineType::AnyTagged(), MachineType::Float64());
1191
1192 CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, MachineType::Int32(),
1193 MachineType::Float64());
1194 CheckChangeInsertion(IrOpcode::kChangeInt32ToTagged, MachineType::Int32(),
1195 MachineType::AnyTagged());
1196
1197 CheckChangeInsertion(IrOpcode::kChangeUint32ToFloat64, MachineType::Uint32(),
1198 MachineType::Float64());
1199 CheckChangeInsertion(IrOpcode::kChangeUint32ToTagged, MachineType::Uint32(),
1200 MachineType::AnyTagged());
1201 }
1202
1203
CheckChangesAroundBinop(TestingGraph * t,const Operator * op,IrOpcode::Value input_change,IrOpcode::Value output_change)1204 static void CheckChangesAroundBinop(TestingGraph* t, const Operator* op,
1205 IrOpcode::Value input_change,
1206 IrOpcode::Value output_change) {
1207 Node* binop =
1208 op->ControlInputCount() == 0
1209 ? t->graph()->NewNode(op, t->p0, t->p1)
1210 : t->graph()->NewNode(op, t->p0, t->p1, t->graph()->start());
1211 t->Return(binop);
1212 t->Lower();
1213 CHECK_EQ(input_change, binop->InputAt(0)->opcode());
1214 CHECK_EQ(input_change, binop->InputAt(1)->opcode());
1215 CHECK_EQ(t->p0, binop->InputAt(0)->InputAt(0));
1216 CHECK_EQ(t->p1, binop->InputAt(1)->InputAt(0));
1217 CHECK_EQ(output_change, t->ret->InputAt(0)->opcode());
1218 CHECK_EQ(binop, t->ret->InputAt(0)->InputAt(0));
1219 }
1220
1221
TEST(InsertChangesAroundInt32Binops)1222 TEST(InsertChangesAroundInt32Binops) {
1223 TestingGraph t(Type::Signed32(), Type::Signed32());
1224
1225 const Operator* ops[] = {t.machine()->Int32Add(), t.machine()->Int32Sub(),
1226 t.machine()->Int32Mul(), t.machine()->Int32Div(),
1227 t.machine()->Int32Mod(), t.machine()->Word32And(),
1228 t.machine()->Word32Or(), t.machine()->Word32Xor(),
1229 t.machine()->Word32Shl(), t.machine()->Word32Sar()};
1230
1231 for (size_t i = 0; i < arraysize(ops); i++) {
1232 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
1233 IrOpcode::kChangeInt32ToTagged);
1234 }
1235 }
1236
1237
TEST(InsertChangesAroundInt32Cmp)1238 TEST(InsertChangesAroundInt32Cmp) {
1239 TestingGraph t(Type::Signed32(), Type::Signed32());
1240
1241 const Operator* ops[] = {t.machine()->Int32LessThan(),
1242 t.machine()->Int32LessThanOrEqual()};
1243
1244 for (size_t i = 0; i < arraysize(ops); i++) {
1245 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
1246 IrOpcode::kChangeBitToBool);
1247 }
1248 }
1249
1250
TEST(InsertChangesAroundUint32Cmp)1251 TEST(InsertChangesAroundUint32Cmp) {
1252 TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
1253
1254 const Operator* ops[] = {t.machine()->Uint32LessThan(),
1255 t.machine()->Uint32LessThanOrEqual()};
1256
1257 for (size_t i = 0; i < arraysize(ops); i++) {
1258 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToUint32,
1259 IrOpcode::kChangeBitToBool);
1260 }
1261 }
1262
1263
TEST(InsertChangesAroundFloat64Binops)1264 TEST(InsertChangesAroundFloat64Binops) {
1265 TestingGraph t(Type::Number(), Type::Number());
1266
1267 const Operator* ops[] = {
1268 t.machine()->Float64Add(), t.machine()->Float64Sub(),
1269 t.machine()->Float64Mul(), t.machine()->Float64Div(),
1270 t.machine()->Float64Mod(),
1271 };
1272
1273 for (size_t i = 0; i < arraysize(ops); i++) {
1274 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64,
1275 IrOpcode::kChangeFloat64ToTagged);
1276 }
1277 }
1278
1279
TEST(InsertChangesAroundFloat64Cmp)1280 TEST(InsertChangesAroundFloat64Cmp) {
1281 TestingGraph t(Type::Number(), Type::Number());
1282
1283 const Operator* ops[] = {t.machine()->Float64Equal(),
1284 t.machine()->Float64LessThan(),
1285 t.machine()->Float64LessThanOrEqual()};
1286
1287 for (size_t i = 0; i < arraysize(ops); i++) {
1288 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64,
1289 IrOpcode::kChangeBitToBool);
1290 }
1291 }
1292
1293
1294 namespace {
1295
CheckFieldAccessArithmetic(FieldAccess access,Node * load_or_store)1296 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
1297 IntPtrMatcher mindex(load_or_store->InputAt(1));
1298 CHECK(mindex.Is(access.offset - access.tag()));
1299 }
1300
1301
CheckElementAccessArithmetic(ElementAccess access,Node * load_or_store)1302 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
1303 Node* index = load_or_store->InputAt(1);
1304 if (kPointerSize == 8) {
1305 CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode());
1306 index = index->InputAt(0);
1307 }
1308
1309 Int32BinopMatcher mindex(index);
1310 CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode());
1311 CHECK(mindex.right().Is(access.header_size - access.tag()));
1312
1313 const int element_size_shift =
1314 ElementSizeLog2Of(access.machine_type.representation());
1315 if (element_size_shift) {
1316 Int32BinopMatcher shl(mindex.left().node());
1317 CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode());
1318 CHECK(shl.right().Is(element_size_shift));
1319 return shl.left().node();
1320 } else {
1321 return mindex.left().node();
1322 }
1323 }
1324
1325
1326 const MachineType kMachineReps[] = {
1327 MachineType::Int8(), MachineType::Int16(), MachineType::Int32(),
1328 MachineType::Uint32(), MachineType::Int64(), MachineType::Float64(),
1329 MachineType::AnyTagged()};
1330
1331 } // namespace
1332
1333
TEST(LowerLoadField_to_load)1334 TEST(LowerLoadField_to_load) {
1335 TestingGraph t(Type::Any(), Type::Signed32());
1336
1337 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
1338 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1339 Handle<Name>::null(), Type::Any(), kMachineReps[i]};
1340
1341 Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0,
1342 t.start, t.start);
1343 Node* use = t.Use(load, kMachineReps[i]);
1344 t.Return(use);
1345 t.LowerAllNodesAndLowerChanges();
1346 CHECK_EQ(IrOpcode::kLoad, load->opcode());
1347 CHECK_EQ(t.p0, load->InputAt(0));
1348 CheckFieldAccessArithmetic(access, load);
1349
1350 MachineType rep = LoadRepresentationOf(load->op());
1351 CHECK_EQ(kMachineReps[i], rep);
1352 }
1353 }
1354
1355
TEST(LowerStoreField_to_store)1356 TEST(LowerStoreField_to_store) {
1357 {
1358 TestingGraph t(Type::Any(), Type::Signed32());
1359
1360 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
1361 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1362 Handle<Name>::null(), Type::Any(), kMachineReps[i]};
1363
1364
1365 Node* val = t.ExampleWithOutput(kMachineReps[i]);
1366 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
1367 val, t.start, t.start);
1368 t.Effect(store);
1369 t.LowerAllNodesAndLowerChanges();
1370 CHECK_EQ(IrOpcode::kStore, store->opcode());
1371 CHECK_EQ(val, store->InputAt(2));
1372 CheckFieldAccessArithmetic(access, store);
1373
1374 StoreRepresentation rep = StoreRepresentationOf(store->op());
1375 if (kMachineReps[i].representation() == MachineRepresentation::kTagged) {
1376 CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
1377 }
1378 CHECK_EQ(kMachineReps[i].representation(), rep.representation());
1379 }
1380 }
1381 {
1382 HandleAndZoneScope scope;
1383 Zone* z = scope.main_zone();
1384 TestingGraph t(Type::Any(), Type::Intersect(Type::SignedSmall(),
1385 Type::TaggedSigned(), z));
1386 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1387 Handle<Name>::null(), Type::Any(),
1388 MachineType::AnyTagged()};
1389 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
1390 t.p1, t.start, t.start);
1391 t.Effect(store);
1392 t.LowerAllNodesAndLowerChanges();
1393 CHECK_EQ(IrOpcode::kStore, store->opcode());
1394 CHECK_EQ(t.p1, store->InputAt(2));
1395 StoreRepresentation rep = StoreRepresentationOf(store->op());
1396 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind());
1397 }
1398 }
1399
1400
TEST(LowerLoadElement_to_load)1401 TEST(LowerLoadElement_to_load) {
1402 TestingGraph t(Type::Any(), Type::Signed32());
1403
1404 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
1405 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1406 Type::Any(), kMachineReps[i]};
1407
1408 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
1409 t.p1, t.start, t.start);
1410 Node* use = t.Use(load, kMachineReps[i]);
1411 t.Return(use);
1412 t.LowerAllNodesAndLowerChanges();
1413 CHECK_EQ(IrOpcode::kLoad, load->opcode());
1414 CHECK_EQ(t.p0, load->InputAt(0));
1415 CheckElementAccessArithmetic(access, load);
1416
1417 MachineType rep = LoadRepresentationOf(load->op());
1418 CHECK_EQ(kMachineReps[i], rep);
1419 }
1420 }
1421
1422
TEST(LowerStoreElement_to_store)1423 TEST(LowerStoreElement_to_store) {
1424 {
1425 TestingGraph t(Type::Any(), Type::Signed32());
1426
1427 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
1428 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1429 Type::Any(), kMachineReps[i]};
1430
1431 Node* val = t.ExampleWithOutput(kMachineReps[i]);
1432 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access),
1433 t.p0, t.p1, val, t.start, t.start);
1434 t.Effect(store);
1435 t.LowerAllNodesAndLowerChanges();
1436 CHECK_EQ(IrOpcode::kStore, store->opcode());
1437 CHECK_EQ(val, store->InputAt(2));
1438 CheckElementAccessArithmetic(access, store);
1439
1440 StoreRepresentation rep = StoreRepresentationOf(store->op());
1441 if (kMachineReps[i].representation() == MachineRepresentation::kTagged) {
1442 CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
1443 }
1444 CHECK_EQ(kMachineReps[i].representation(), rep.representation());
1445 }
1446 }
1447 {
1448 HandleAndZoneScope scope;
1449 Zone* z = scope.main_zone();
1450 TestingGraph t(
1451 Type::Any(), Type::Signed32(),
1452 Type::Intersect(Type::SignedSmall(), Type::TaggedSigned(), z));
1453 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1454 Type::Any(), MachineType::AnyTagged()};
1455 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
1456 t.p1, t.p2, t.start, t.start);
1457 t.Effect(store);
1458 t.LowerAllNodesAndLowerChanges();
1459 CHECK_EQ(IrOpcode::kStore, store->opcode());
1460 CHECK_EQ(t.p2, store->InputAt(2));
1461 StoreRepresentation rep = StoreRepresentationOf(store->op());
1462 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind());
1463 }
1464 }
1465
1466
TEST(InsertChangeForLoadElementIndex)1467 TEST(InsertChangeForLoadElementIndex) {
1468 // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
1469 // Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
1470 TestingGraph t(Type::Any(), Type::Signed32());
1471 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
1472 MachineType::AnyTagged()};
1473
1474 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
1475 t.p1, t.start, t.start);
1476 t.Return(load);
1477 t.Lower();
1478 CHECK_EQ(IrOpcode::kLoadElement, load->opcode());
1479 CHECK_EQ(t.p0, load->InputAt(0));
1480 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, load->InputAt(1));
1481 }
1482
1483
TEST(InsertChangeForStoreElementIndex)1484 TEST(InsertChangeForStoreElementIndex) {
1485 // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
1486 // Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
1487 TestingGraph t(Type::Any(), Type::Signed32());
1488 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
1489 MachineType::AnyTagged()};
1490
1491 Node* store =
1492 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
1493 t.jsgraph.TrueConstant(), t.start, t.start);
1494 t.Effect(store);
1495 t.Lower();
1496 CHECK_EQ(IrOpcode::kStoreElement, store->opcode());
1497 CHECK_EQ(t.p0, store->InputAt(0));
1498 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, store->InputAt(1));
1499 }
1500
1501
TEST(InsertChangeForLoadElement)1502 TEST(InsertChangeForLoadElement) {
1503 // TODO(titzer): test all load/store representation change insertions.
1504 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
1505 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
1506 MachineType::Float64()};
1507
1508 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
1509 t.p1, t.start, t.start);
1510 t.Return(load);
1511 t.Lower();
1512 CHECK_EQ(IrOpcode::kLoadElement, load->opcode());
1513 CHECK_EQ(t.p0, load->InputAt(0));
1514 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
1515 }
1516
1517
TEST(InsertChangeForLoadField)1518 TEST(InsertChangeForLoadField) {
1519 // TODO(titzer): test all load/store representation change insertions.
1520 TestingGraph t(Type::Any(), Type::Signed32());
1521 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1522 Handle<Name>::null(), Type::Any(),
1523 MachineType::Float64()};
1524
1525 Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0,
1526 t.start, t.start);
1527 t.Return(load);
1528 t.Lower();
1529 CHECK_EQ(IrOpcode::kLoadField, load->opcode());
1530 CHECK_EQ(t.p0, load->InputAt(0));
1531 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
1532 }
1533
1534
TEST(InsertChangeForStoreElement)1535 TEST(InsertChangeForStoreElement) {
1536 // TODO(titzer): test all load/store representation change insertions.
1537 TestingGraph t(Type::Any(), Type::Signed32());
1538 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
1539 MachineType::Float64()};
1540
1541 Node* store =
1542 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
1543 t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
1544 t.Effect(store);
1545 t.Lower();
1546
1547 CHECK_EQ(IrOpcode::kStoreElement, store->opcode());
1548 CHECK_EQ(t.p0, store->InputAt(0));
1549 CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
1550 }
1551
1552
TEST(InsertChangeForStoreField)1553 TEST(InsertChangeForStoreField) {
1554 // TODO(titzer): test all load/store representation change insertions.
1555 TestingGraph t(Type::Any(), Type::Signed32());
1556 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1557 Handle<Name>::null(), Type::Any(),
1558 MachineType::Float64()};
1559
1560 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
1561 t.p1, t.start, t.start);
1562 t.Effect(store);
1563 t.Lower();
1564
1565 CHECK_EQ(IrOpcode::kStoreField, store->opcode());
1566 CHECK_EQ(t.p0, store->InputAt(0));
1567 CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(1));
1568 }
1569
1570
TEST(UpdatePhi)1571 TEST(UpdatePhi) {
1572 TestingGraph t(Type::Any(), Type::Signed32());
1573 static const MachineType kMachineTypes[] = {
1574 MachineType::Int32(), MachineType::Uint32(), MachineType::Float64()};
1575 Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()};
1576
1577 for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
1578 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1579 Handle<Name>::null(), kTypes[i], kMachineTypes[i]};
1580
1581 Node* load0 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0,
1582 t.start, t.start);
1583 Node* load1 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p1,
1584 t.start, t.start);
1585 Node* phi =
1586 t.graph()->NewNode(t.common()->Phi(MachineRepresentation::kTagged, 2),
1587 load0, load1, t.start);
1588 t.Return(t.Use(phi, kMachineTypes[i]));
1589 t.Lower();
1590
1591 CHECK_EQ(IrOpcode::kPhi, phi->opcode());
1592 CHECK_EQ(kMachineTypes[i].representation(), PhiRepresentationOf(phi->op()));
1593 }
1594 }
1595
1596
TEST(RunNumberDivide_minus_1_TruncatingToInt32)1597 TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
1598 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1599 Node* num = t.NumberToInt32(t.Parameter(0));
1600 Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
1601 Node* trunc = t.NumberToInt32(div);
1602 t.Return(trunc);
1603
1604 t.LowerAllNodesAndLowerChanges();
1605 t.GenerateCode();
1606
1607 FOR_INT32_INPUTS(i) {
1608 int32_t x = 0 - *i;
1609 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1610 }
1611 }
1612
1613
TEST(RunNumberMultiply_TruncatingToInt32)1614 TEST(RunNumberMultiply_TruncatingToInt32) {
1615 int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
1616
1617 for (size_t i = 0; i < arraysize(constants); i++) {
1618 double k = static_cast<double>(constants[i]);
1619 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1620 Node* num = t.NumberToInt32(t.Parameter(0));
1621 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
1622 Node* trunc = t.NumberToInt32(mul);
1623 t.Return(trunc);
1624
1625 t.LowerAllNodesAndLowerChanges();
1626 t.GenerateCode();
1627
1628 FOR_INT32_INPUTS(i) {
1629 int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
1630 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1631 }
1632 }
1633 }
1634
1635
TEST(RunNumberMultiply_TruncatingToUint32)1636 TEST(RunNumberMultiply_TruncatingToUint32) {
1637 uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
1638
1639 for (size_t i = 0; i < arraysize(constants); i++) {
1640 double k = static_cast<double>(constants[i]);
1641 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1642 Node* num = t.NumberToUint32(t.Parameter(0));
1643 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
1644 Node* trunc = t.NumberToUint32(mul);
1645 t.Return(trunc);
1646
1647 t.LowerAllNodesAndLowerChanges();
1648 t.GenerateCode();
1649
1650 FOR_UINT32_INPUTS(i) {
1651 uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
1652 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1653 }
1654 }
1655 }
1656
1657
TEST(RunNumberDivide_2_TruncatingToUint32)1658 TEST(RunNumberDivide_2_TruncatingToUint32) {
1659 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1660 Node* num = t.NumberToUint32(t.Parameter(0));
1661 Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
1662 Node* trunc = t.NumberToUint32(div);
1663 t.Return(trunc);
1664
1665 t.LowerAllNodesAndLowerChanges();
1666 t.GenerateCode();
1667
1668 FOR_UINT32_INPUTS(i) {
1669 uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
1670 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1671 }
1672 }
1673
1674
TEST(NumberMultiply_ConstantOutOfRange)1675 TEST(NumberMultiply_ConstantOutOfRange) {
1676 TestingGraph t(Type::Signed32());
1677 Node* k = t.jsgraph.Constant(1000000023);
1678 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
1679 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
1680 t.Return(trunc);
1681 t.Lower();
1682
1683 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
1684 }
1685
1686
TEST(NumberMultiply_NonTruncating)1687 TEST(NumberMultiply_NonTruncating) {
1688 TestingGraph t(Type::Signed32());
1689 Node* k = t.jsgraph.Constant(111);
1690 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
1691 t.Return(mul);
1692 t.Lower();
1693
1694 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
1695 }
1696
1697
TEST(NumberDivide_TruncatingToInt32)1698 TEST(NumberDivide_TruncatingToInt32) {
1699 int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
1700
1701 for (size_t i = 0; i < arraysize(constants); i++) {
1702 TestingGraph t(Type::Signed32());
1703 Node* k = t.jsgraph.Constant(constants[i]);
1704 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
1705 Node* use = t.Use(div, MachineType::Int32());
1706 t.Return(use);
1707 t.Lower();
1708
1709 CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
1710 }
1711 }
1712
1713
TEST(RunNumberDivide_TruncatingToInt32)1714 TEST(RunNumberDivide_TruncatingToInt32) {
1715 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
1716
1717 for (size_t i = 0; i < arraysize(constants); i++) {
1718 int32_t k = constants[i];
1719 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1720 Node* num = t.NumberToInt32(t.Parameter(0));
1721 Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
1722 Node* trunc = t.NumberToInt32(div);
1723 t.Return(trunc);
1724
1725 t.LowerAllNodesAndLowerChanges();
1726 t.GenerateCode();
1727
1728 FOR_INT32_INPUTS(i) {
1729 if (*i == INT_MAX) continue; // exclude max int.
1730 int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
1731 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1732 }
1733 }
1734 }
1735
1736
TEST(NumberDivide_TruncatingToUint32)1737 TEST(NumberDivide_TruncatingToUint32) {
1738 double constants[] = {1, 3, 100, 1000, 100998348};
1739
1740 for (size_t i = 0; i < arraysize(constants); i++) {
1741 TestingGraph t(Type::Unsigned32());
1742 Node* k = t.jsgraph.Constant(constants[i]);
1743 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
1744 Node* use = t.Use(div, MachineType::Uint32());
1745 t.Return(use);
1746 t.Lower();
1747
1748 CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
1749 }
1750 }
1751
1752
TEST(RunNumberDivide_TruncatingToUint32)1753 TEST(RunNumberDivide_TruncatingToUint32) {
1754 uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
1755
1756 for (size_t i = 0; i < arraysize(constants); i++) {
1757 uint32_t k = constants[i];
1758 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1759 Node* num = t.NumberToUint32(t.Parameter(0));
1760 Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
1761 Node* trunc = t.NumberToUint32(div);
1762 t.Return(trunc);
1763
1764 t.LowerAllNodesAndLowerChanges();
1765 t.GenerateCode();
1766
1767 FOR_UINT32_INPUTS(i) {
1768 uint32_t x = *i / k;
1769 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1770 }
1771 }
1772 }
1773
1774
TEST(NumberDivide_BadConstants)1775 TEST(NumberDivide_BadConstants) {
1776 {
1777 TestingGraph t(Type::Signed32());
1778 Node* k = t.jsgraph.Constant(-1);
1779 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
1780 Node* use = t.Use(div, MachineType::Int32());
1781 t.Return(use);
1782 t.Lower();
1783
1784 CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
1785 }
1786
1787 {
1788 TestingGraph t(Type::Signed32());
1789 Node* k = t.jsgraph.Constant(0);
1790 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
1791 Node* use = t.Use(div, MachineType::Int32());
1792 t.Return(use);
1793 t.Lower();
1794
1795 CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
1796 CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
1797 }
1798
1799 {
1800 TestingGraph t(Type::Unsigned32());
1801 Node* k = t.jsgraph.Constant(0);
1802 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
1803 Node* use = t.Use(div, MachineType::Uint32());
1804 t.Return(use);
1805 t.Lower();
1806
1807 CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
1808 CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
1809 }
1810 }
1811
1812
TEST(NumberModulus_TruncatingToInt32)1813 TEST(NumberModulus_TruncatingToInt32) {
1814 int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
1815
1816 for (size_t i = 0; i < arraysize(constants); i++) {
1817 TestingGraph t(Type::Signed32());
1818 Node* k = t.jsgraph.Constant(constants[i]);
1819 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1820 Node* use = t.Use(mod, MachineType::Int32());
1821 t.Return(use);
1822 t.Lower();
1823
1824 CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
1825 }
1826 }
1827
1828
TEST(RunNumberModulus_TruncatingToInt32)1829 TEST(RunNumberModulus_TruncatingToInt32) {
1830 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
1831
1832 for (size_t i = 0; i < arraysize(constants); i++) {
1833 int32_t k = constants[i];
1834 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1835 Node* num = t.NumberToInt32(t.Parameter(0));
1836 Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
1837 Node* trunc = t.NumberToInt32(mod);
1838 t.Return(trunc);
1839
1840 t.LowerAllNodesAndLowerChanges();
1841 t.GenerateCode();
1842
1843 FOR_INT32_INPUTS(i) {
1844 if (*i == INT_MAX) continue; // exclude max int.
1845 int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
1846 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1847 }
1848 }
1849 }
1850
1851
TEST(NumberModulus_TruncatingToUint32)1852 TEST(NumberModulus_TruncatingToUint32) {
1853 double constants[] = {1, 3, 100, 1000, 100998348};
1854
1855 for (size_t i = 0; i < arraysize(constants); i++) {
1856 TestingGraph t(Type::Unsigned32());
1857 Node* k = t.jsgraph.Constant(constants[i]);
1858 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1859 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
1860 t.Return(trunc);
1861 t.Lower();
1862
1863 CHECK_EQ(IrOpcode::kUint32Mod, t.ret->InputAt(0)->InputAt(0)->opcode());
1864 }
1865 }
1866
1867
TEST(RunNumberModulus_TruncatingToUint32)1868 TEST(RunNumberModulus_TruncatingToUint32) {
1869 uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
1870
1871 for (size_t i = 0; i < arraysize(constants); i++) {
1872 uint32_t k = constants[i];
1873 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
1874 Node* num = t.NumberToUint32(t.Parameter(0));
1875 Node* mod =
1876 t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
1877 Node* trunc = t.NumberToUint32(mod);
1878 t.Return(trunc);
1879
1880 t.LowerAllNodesAndLowerChanges();
1881 t.GenerateCode();
1882
1883 FOR_UINT32_INPUTS(i) {
1884 uint32_t x = *i % k;
1885 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1886 }
1887 }
1888 }
1889
1890
TEST(NumberModulus_Int32)1891 TEST(NumberModulus_Int32) {
1892 int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
1893
1894 for (size_t i = 0; i < arraysize(constants); i++) {
1895 TestingGraph t(Type::Signed32());
1896 Node* k = t.jsgraph.Constant(constants[i]);
1897 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1898 t.Return(mod);
1899 t.Lower();
1900
1901 CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); // Pesky -0 behavior.
1902 }
1903 }
1904
1905
TEST(NumberModulus_Uint32)1906 TEST(NumberModulus_Uint32) {
1907 const double kConstants[] = {2, 100, 1000, 1024, 2048};
1908 const MachineType kTypes[] = {MachineType::Int32(), MachineType::Uint32()};
1909
1910 for (auto const type : kTypes) {
1911 for (auto const c : kConstants) {
1912 TestingGraph t(Type::Unsigned32());
1913 Node* k = t.jsgraph.Constant(c);
1914 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1915 Node* use = t.Use(mod, type);
1916 t.Return(use);
1917 t.Lower();
1918
1919 CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode());
1920 }
1921 }
1922 }
1923
1924
TEST(PhiRepresentation)1925 TEST(PhiRepresentation) {
1926 HandleAndZoneScope scope;
1927 Zone* z = scope.main_zone();
1928
1929 struct TestData {
1930 Type* arg1;
1931 Type* arg2;
1932 MachineType use;
1933 MachineRepresentation expected;
1934 };
1935
1936 TestData test_data[] = {
1937 {Type::Signed32(), Type::Unsigned32(), MachineType::Int32(),
1938 MachineRepresentation::kWord32},
1939 {Type::Signed32(), Type::Unsigned32(), MachineType::Uint32(),
1940 MachineRepresentation::kWord32},
1941 {Type::Signed32(), Type::Signed32(), MachineType::Int32(),
1942 MachineRepresentation::kWord32},
1943 {Type::Unsigned32(), Type::Unsigned32(), MachineType::Int32(),
1944 MachineRepresentation::kWord32},
1945 {Type::Number(), Type::Signed32(), MachineType::Int32(),
1946 MachineRepresentation::kWord32}};
1947
1948 for (auto const d : test_data) {
1949 TestingGraph t(d.arg1, d.arg2, Type::Boolean());
1950
1951 Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start);
1952 Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br);
1953 Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br);
1954 Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb);
1955
1956 Node* phi = t.graph()->NewNode(
1957 t.common()->Phi(MachineRepresentation::kTagged, 2), t.p0, t.p1, m);
1958
1959 Type* phi_type = Type::Union(d.arg1, d.arg2, z);
1960 NodeProperties::SetType(phi, phi_type);
1961
1962 Node* use = t.Use(phi, d.use);
1963 t.Return(use);
1964 t.Lower();
1965
1966 CHECK_EQ(d.expected, PhiRepresentationOf(phi->op()));
1967 }
1968 }
1969
1970 } // namespace compiler
1971 } // namespace internal
1972 } // namespace v8
1973