• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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