Home | History | Annotate | Download | only in compiler
      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/compiler/access-builder.h"
      8 #include "src/compiler/control-builders.h"
      9 #include "src/compiler/generic-node-inl.h"
     10 #include "src/compiler/graph-visualizer.h"
     11 #include "src/compiler/node-properties-inl.h"
     12 #include "src/compiler/pipeline.h"
     13 #include "src/compiler/representation-change.h"
     14 #include "src/compiler/simplified-lowering.h"
     15 #include "src/compiler/typer.h"
     16 #include "src/compiler/verifier.h"
     17 #include "src/execution.h"
     18 #include "src/parser.h"
     19 #include "src/rewriter.h"
     20 #include "src/scopes.h"
     21 #include "test/cctest/cctest.h"
     22 #include "test/cctest/compiler/codegen-tester.h"
     23 #include "test/cctest/compiler/graph-builder-tester.h"
     24 #include "test/cctest/compiler/value-helper.h"
     25 
     26 using namespace v8::internal;
     27 using namespace v8::internal::compiler;
     28 
     29 template <typename ReturnType>
     30 class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> {
     31  public:
     32   SimplifiedLoweringTester(MachineType p0 = kMachNone,
     33                            MachineType p1 = kMachNone,
     34                            MachineType p2 = kMachNone,
     35                            MachineType p3 = kMachNone,
     36                            MachineType p4 = kMachNone)
     37       : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4),
     38         typer(this->zone()),
     39         javascript(this->zone()),
     40         jsgraph(this->graph(), this->common(), &javascript, &typer,
     41                 this->machine()),
     42         lowering(&jsgraph) {}
     43 
     44   Typer typer;
     45   JSOperatorBuilder javascript;
     46   JSGraph jsgraph;
     47   SimplifiedLowering lowering;
     48 
     49   void LowerAllNodes() {
     50     this->End();
     51     lowering.LowerAllNodes();
     52   }
     53 
     54   Factory* factory() { return this->isolate()->factory(); }
     55   Heap* heap() { return this->isolate()->heap(); }
     56 };
     57 
     58 
     59 #ifndef V8_TARGET_ARCH_ARM64
     60 // TODO(titzer): these result in a stub call that doesn't work on ARM64.
     61 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
     62 // TODO(titzer): test tagged representation for input to NumberToInt32.
     63 TEST(RunNumberToInt32_float64) {
     64   // TODO(titzer): explicit load/stores here are only because of representations
     65   double input;
     66   int32_t result;
     67   SimplifiedLoweringTester<Object*> t;
     68   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
     69                       kMachFloat64};
     70   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
     71   Node* convert = t.NumberToInt32(loaded);
     72   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
     73                        kMachInt32};
     74   t.StoreField(store, t.PointerConstant(&result), convert);
     75   t.Return(t.jsgraph.TrueConstant());
     76   t.LowerAllNodes();
     77   t.GenerateCode();
     78 
     79   if (Pipeline::SupportedTarget()) {
     80     FOR_FLOAT64_INPUTS(i) {
     81       input = *i;
     82       int32_t expected = DoubleToInt32(*i);
     83       t.Call();
     84       CHECK_EQ(expected, result);
     85     }
     86   }
     87 }
     88 
     89 
     90 // TODO(titzer): test tagged representation for input to NumberToUint32.
     91 TEST(RunNumberToUint32_float64) {
     92   // TODO(titzer): explicit load/stores here are only because of representations
     93   double input;
     94   uint32_t result;
     95   SimplifiedLoweringTester<Object*> t;
     96   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
     97                       kMachFloat64};
     98   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
     99   Node* convert = t.NumberToUint32(loaded);
    100   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
    101                        kMachUint32};
    102   t.StoreField(store, t.PointerConstant(&result), convert);
    103   t.Return(t.jsgraph.TrueConstant());
    104   t.LowerAllNodes();
    105   t.GenerateCode();
    106 
    107   if (Pipeline::SupportedTarget()) {
    108     FOR_FLOAT64_INPUTS(i) {
    109       input = *i;
    110       uint32_t expected = DoubleToUint32(*i);
    111       t.Call();
    112       CHECK_EQ(static_cast<int32_t>(expected), static_cast<int32_t>(result));
    113     }
    114   }
    115 }
    116 #endif
    117 
    118 
    119 // Create a simple JSObject with a unique map.
    120 static Handle<JSObject> TestObject() {
    121   static int index = 0;
    122   char buffer[50];
    123   v8::base::OS::SNPrintF(buffer, 50, "({'a_%d':1})", index++);
    124   return Handle<JSObject>::cast(v8::Utils::OpenHandle(*CompileRun(buffer)));
    125 }
    126 
    127 
    128 TEST(RunLoadMap) {
    129   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
    130   FieldAccess access = AccessBuilder::ForMap();
    131   Node* load = t.LoadField(access, t.Parameter(0));
    132   t.Return(load);
    133 
    134   t.LowerAllNodes();
    135   t.GenerateCode();
    136 
    137   if (Pipeline::SupportedTarget()) {
    138     Handle<JSObject> src = TestObject();
    139     Handle<Map> src_map(src->map());
    140     Object* result = t.Call(*src);  // TODO(titzer): raw pointers in call
    141     CHECK_EQ(*src_map, result);
    142   }
    143 }
    144 
    145 
    146 TEST(RunStoreMap) {
    147   SimplifiedLoweringTester<int32_t> t(kMachAnyTagged, kMachAnyTagged);
    148   FieldAccess access = AccessBuilder::ForMap();
    149   t.StoreField(access, t.Parameter(1), t.Parameter(0));
    150   t.Return(t.jsgraph.TrueConstant());
    151 
    152   t.LowerAllNodes();
    153   t.GenerateCode();
    154 
    155   if (Pipeline::SupportedTarget()) {
    156     Handle<JSObject> src = TestObject();
    157     Handle<Map> src_map(src->map());
    158     Handle<JSObject> dst = TestObject();
    159     CHECK(src->map() != dst->map());
    160     t.Call(*src_map, *dst);  // TODO(titzer): raw pointers in call
    161     CHECK(*src_map == dst->map());
    162   }
    163 }
    164 
    165 
    166 TEST(RunLoadProperties) {
    167   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
    168   FieldAccess access = AccessBuilder::ForJSObjectProperties();
    169   Node* load = t.LoadField(access, t.Parameter(0));
    170   t.Return(load);
    171 
    172   t.LowerAllNodes();
    173   t.GenerateCode();
    174 
    175   if (Pipeline::SupportedTarget()) {
    176     Handle<JSObject> src = TestObject();
    177     Handle<FixedArray> src_props(src->properties());
    178     Object* result = t.Call(*src);  // TODO(titzer): raw pointers in call
    179     CHECK_EQ(*src_props, result);
    180   }
    181 }
    182 
    183 
    184 TEST(RunLoadStoreMap) {
    185   SimplifiedLoweringTester<Object*> t(kMachAnyTagged, kMachAnyTagged);
    186   FieldAccess access = AccessBuilder::ForMap();
    187   Node* load = t.LoadField(access, t.Parameter(0));
    188   t.StoreField(access, t.Parameter(1), load);
    189   t.Return(load);
    190 
    191   t.LowerAllNodes();
    192   t.GenerateCode();
    193 
    194   if (Pipeline::SupportedTarget()) {
    195     Handle<JSObject> src = TestObject();
    196     Handle<Map> src_map(src->map());
    197     Handle<JSObject> dst = TestObject();
    198     CHECK(src->map() != dst->map());
    199     Object* result = t.Call(*src, *dst);  // TODO(titzer): raw pointers in call
    200     CHECK(result->IsMap());
    201     CHECK_EQ(*src_map, result);
    202     CHECK(*src_map == dst->map());
    203   }
    204 }
    205 
    206 
    207 TEST(RunLoadStoreFixedArrayIndex) {
    208   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
    209   ElementAccess access = AccessBuilder::ForFixedArrayElement();
    210   Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
    211                              t.Int32Constant(2));
    212   t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
    213                  load);
    214   t.Return(load);
    215 
    216   t.LowerAllNodes();
    217   t.GenerateCode();
    218 
    219   if (Pipeline::SupportedTarget()) {
    220     Handle<FixedArray> array = t.factory()->NewFixedArray(2);
    221     Handle<JSObject> src = TestObject();
    222     Handle<JSObject> dst = TestObject();
    223     array->set(0, *src);
    224     array->set(1, *dst);
    225     Object* result = t.Call(*array);
    226     CHECK_EQ(*src, result);
    227     CHECK_EQ(*src, array->get(0));
    228     CHECK_EQ(*src, array->get(1));
    229   }
    230 }
    231 
    232 
    233 TEST(RunLoadStoreArrayBuffer) {
    234   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
    235   const int index = 12;
    236   const int array_length = 2 * index;
    237   ElementAccess buffer_access =
    238       AccessBuilder::ForBackingStoreElement(kMachInt8);
    239   Node* backing_store = t.LoadField(
    240       AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
    241   Node* load =
    242       t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
    243                     t.Int32Constant(array_length));
    244   t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
    245                  t.Int32Constant(array_length), load);
    246   t.Return(t.jsgraph.TrueConstant());
    247 
    248   t.LowerAllNodes();
    249   t.GenerateCode();
    250 
    251   if (Pipeline::SupportedTarget()) {
    252     Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer();
    253     Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length);
    254     uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store());
    255     for (int i = 0; i < array_length; i++) {
    256       data[i] = i;
    257     }
    258 
    259     // TODO(titzer): raw pointers in call
    260     Object* result = t.Call(*array);
    261     CHECK_EQ(t.isolate()->heap()->true_value(), result);
    262     for (int i = 0; i < array_length; i++) {
    263       uint8_t expected = i;
    264       if (i == (index + 1)) expected = index;
    265       CHECK_EQ(data[i], expected);
    266     }
    267   }
    268 }
    269 
    270 
    271 TEST(RunLoadFieldFromUntaggedBase) {
    272   Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
    273 
    274   for (size_t i = 0; i < arraysize(smis); i++) {
    275     int offset = static_cast<int>(i * sizeof(Smi*));
    276     FieldAccess access = {kUntaggedBase, offset, Handle<Name>(),
    277                           Type::Integral32(), kMachAnyTagged};
    278 
    279     SimplifiedLoweringTester<Object*> t;
    280     Node* load = t.LoadField(access, t.PointerConstant(smis));
    281     t.Return(load);
    282     t.LowerAllNodes();
    283 
    284     if (!Pipeline::SupportedTarget()) continue;
    285 
    286     for (int j = -5; j <= 5; j++) {
    287       Smi* expected = Smi::FromInt(j);
    288       smis[i] = expected;
    289       CHECK_EQ(expected, t.Call());
    290     }
    291   }
    292 }
    293 
    294 
    295 TEST(RunStoreFieldToUntaggedBase) {
    296   Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
    297 
    298   for (size_t i = 0; i < arraysize(smis); i++) {
    299     int offset = static_cast<int>(i * sizeof(Smi*));
    300     FieldAccess access = {kUntaggedBase, offset, Handle<Name>(),
    301                           Type::Integral32(), kMachAnyTagged};
    302 
    303     SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
    304     Node* p0 = t.Parameter(0);
    305     t.StoreField(access, t.PointerConstant(smis), p0);
    306     t.Return(p0);
    307     t.LowerAllNodes();
    308 
    309     if (!Pipeline::SupportedTarget()) continue;
    310 
    311     for (int j = -5; j <= 5; j++) {
    312       Smi* expected = Smi::FromInt(j);
    313       smis[i] = Smi::FromInt(-100);
    314       CHECK_EQ(expected, t.Call(expected));
    315       CHECK_EQ(expected, smis[i]);
    316     }
    317   }
    318 }
    319 
    320 
    321 TEST(RunLoadElementFromUntaggedBase) {
    322   Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
    323                  Smi::FromInt(4), Smi::FromInt(5)};
    324 
    325   for (size_t i = 0; i < arraysize(smis); i++) {    // for header sizes
    326     for (size_t j = 0; (i + j) < arraysize(smis); j++) {  // for element index
    327       int offset = static_cast<int>(i * sizeof(Smi*));
    328       ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
    329                               kMachAnyTagged};
    330 
    331       SimplifiedLoweringTester<Object*> t;
    332       Node* load = t.LoadElement(
    333           access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
    334           t.Int32Constant(static_cast<int>(arraysize(smis))));
    335       t.Return(load);
    336       t.LowerAllNodes();
    337 
    338       if (!Pipeline::SupportedTarget()) continue;
    339 
    340       for (int k = -5; k <= 5; k++) {
    341         Smi* expected = Smi::FromInt(k);
    342         smis[i + j] = expected;
    343         CHECK_EQ(expected, t.Call());
    344       }
    345     }
    346   }
    347 }
    348 
    349 
    350 TEST(RunStoreElementFromUntaggedBase) {
    351   Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
    352                  Smi::FromInt(4), Smi::FromInt(5)};
    353 
    354   for (size_t i = 0; i < arraysize(smis); i++) {    // for header sizes
    355     for (size_t j = 0; (i + j) < arraysize(smis); j++) {  // for element index
    356       int offset = static_cast<int>(i * sizeof(Smi*));
    357       ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
    358                               kMachAnyTagged};
    359 
    360       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
    361       Node* p0 = t.Parameter(0);
    362       t.StoreElement(access, t.PointerConstant(smis),
    363                      t.Int32Constant(static_cast<int>(j)),
    364                      t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
    365       t.Return(p0);
    366       t.LowerAllNodes();
    367 
    368       if (!Pipeline::SupportedTarget()) continue;
    369 
    370       for (int k = -5; k <= 5; k++) {
    371         Smi* expected = Smi::FromInt(k);
    372         smis[i + j] = Smi::FromInt(-100);
    373         CHECK_EQ(expected, t.Call(expected));
    374         CHECK_EQ(expected, smis[i + j]);
    375       }
    376 
    377       // TODO(titzer): assert the contents of the array.
    378     }
    379   }
    380 }
    381 
    382 
    383 // A helper class for accessing fields and elements of various types, on both
    384 // tagged and untagged base pointers. Contains both tagged and untagged buffers
    385 // for testing direct memory access from generated code.
    386 template <typename E>
    387 class AccessTester : public HandleAndZoneScope {
    388  public:
    389   bool tagged;
    390   MachineType rep;
    391   E* original_elements;
    392   size_t num_elements;
    393   E* untagged_array;
    394   Handle<ByteArray> tagged_array;  // TODO(titzer): use FixedArray for tagged.
    395 
    396   AccessTester(bool t, MachineType r, E* orig, size_t num)
    397       : tagged(t),
    398         rep(r),
    399         original_elements(orig),
    400         num_elements(num),
    401         untagged_array(static_cast<E*>(malloc(ByteSize()))),
    402         tagged_array(main_isolate()->factory()->NewByteArray(
    403             static_cast<int>(ByteSize()))) {
    404     Reinitialize();
    405   }
    406 
    407   ~AccessTester() { free(untagged_array); }
    408 
    409   size_t ByteSize() { return num_elements * sizeof(E); }
    410 
    411   // Nuke both {untagged_array} and {tagged_array} with {original_elements}.
    412   void Reinitialize() {
    413     memcpy(untagged_array, original_elements, ByteSize());
    414     CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length());
    415     E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress());
    416     memcpy(raw, original_elements, ByteSize());
    417   }
    418 
    419   // Create and run code that copies the element in either {untagged_array}
    420   // or {tagged_array} at index {from_index} to index {to_index}.
    421   void RunCopyElement(int from_index, int to_index) {
    422     // TODO(titzer): test element and field accesses where the base is not
    423     // a constant in the code.
    424     BoundsCheck(from_index);
    425     BoundsCheck(to_index);
    426     ElementAccess access = GetElementAccess();
    427 
    428     SimplifiedLoweringTester<Object*> t;
    429     Node* ptr = GetBaseNode(&t);
    430     Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
    431                                t.Int32Constant(static_cast<int>(num_elements)));
    432     t.StoreElement(access, ptr, t.Int32Constant(to_index),
    433                    t.Int32Constant(static_cast<int>(num_elements)), load);
    434     t.Return(t.jsgraph.TrueConstant());
    435     t.LowerAllNodes();
    436     t.GenerateCode();
    437 
    438     if (Pipeline::SupportedTarget()) {
    439       Object* result = t.Call();
    440       CHECK_EQ(t.isolate()->heap()->true_value(), result);
    441     }
    442   }
    443 
    444   // Create and run code that copies the field in either {untagged_array}
    445   // or {tagged_array} at index {from_index} to index {to_index}.
    446   void RunCopyField(int from_index, int to_index) {
    447     BoundsCheck(from_index);
    448     BoundsCheck(to_index);
    449     FieldAccess from_access = GetFieldAccess(from_index);
    450     FieldAccess to_access = GetFieldAccess(to_index);
    451 
    452     SimplifiedLoweringTester<Object*> t;
    453     Node* ptr = GetBaseNode(&t);
    454     Node* load = t.LoadField(from_access, ptr);
    455     t.StoreField(to_access, ptr, load);
    456     t.Return(t.jsgraph.TrueConstant());
    457     t.LowerAllNodes();
    458     t.GenerateCode();
    459 
    460     if (Pipeline::SupportedTarget()) {
    461       Object* result = t.Call();
    462       CHECK_EQ(t.isolate()->heap()->true_value(), result);
    463     }
    464   }
    465 
    466   // Create and run code that copies the elements from {this} to {that}.
    467   void RunCopyElements(AccessTester<E>* that) {
    468 // TODO(titzer): Rewrite this test without StructuredGraphBuilder support.
    469 #if 0
    470     SimplifiedLoweringTester<Object*> t;
    471 
    472     Node* one = t.Int32Constant(1);
    473     Node* index = t.Int32Constant(0);
    474     Node* limit = t.Int32Constant(static_cast<int>(num_elements));
    475     t.environment()->Push(index);
    476     Node* src = this->GetBaseNode(&t);
    477     Node* dst = that->GetBaseNode(&t);
    478     {
    479       LoopBuilder loop(&t);
    480       loop.BeginLoop();
    481       // Loop exit condition
    482       index = t.environment()->Top();
    483       Node* condition = t.Int32LessThan(index, limit);
    484       loop.BreakUnless(condition);
    485       // dst[index] = src[index]
    486       index = t.environment()->Pop();
    487       Node* load = t.LoadElement(this->GetElementAccess(), src, index);
    488       t.StoreElement(that->GetElementAccess(), dst, index, load);
    489       // index++
    490       index = t.Int32Add(index, one);
    491       t.environment()->Push(index);
    492       // continue
    493       loop.EndBody();
    494       loop.EndLoop();
    495     }
    496     index = t.environment()->Pop();
    497     t.Return(t.jsgraph.TrueConstant());
    498     t.LowerAllNodes();
    499     t.GenerateCode();
    500 
    501     if (Pipeline::SupportedTarget()) {
    502       Object* result = t.Call();
    503       CHECK_EQ(t.isolate()->heap()->true_value(), result);
    504     }
    505 #endif
    506   }
    507 
    508   E GetElement(int index) {
    509     BoundsCheck(index);
    510     if (tagged) {
    511       E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress());
    512       return raw[index];
    513     } else {
    514       return untagged_array[index];
    515     }
    516   }
    517 
    518  private:
    519   ElementAccess GetElementAccess() {
    520     ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase,
    521                             tagged ? FixedArrayBase::kHeaderSize : 0,
    522                             Type::Any(), rep};
    523     return access;
    524   }
    525 
    526   FieldAccess GetFieldAccess(int field) {
    527     int offset = field * sizeof(E);
    528     FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase,
    529                           offset + (tagged ? FixedArrayBase::kHeaderSize : 0),
    530                           Handle<Name>(), Type::Any(), rep};
    531     return access;
    532   }
    533 
    534   template <typename T>
    535   Node* GetBaseNode(SimplifiedLoweringTester<T>* t) {
    536     return tagged ? t->HeapConstant(tagged_array)
    537                   : t->PointerConstant(untagged_array);
    538   }
    539 
    540   void BoundsCheck(int index) {
    541     CHECK_GE(index, 0);
    542     CHECK_LT(index, static_cast<int>(num_elements));
    543     CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length());
    544   }
    545 };
    546 
    547 
    548 template <typename E>
    549 static void RunAccessTest(MachineType rep, E* original_elements, size_t num) {
    550   int num_elements = static_cast<int>(num);
    551 
    552   for (int taggedness = 0; taggedness < 2; taggedness++) {
    553     AccessTester<E> a(taggedness == 1, rep, original_elements, num);
    554     for (int field = 0; field < 2; field++) {
    555       for (int i = 0; i < num_elements - 1; i++) {
    556         a.Reinitialize();
    557         if (field == 0) {
    558           a.RunCopyField(i, i + 1);  // Test field read/write.
    559         } else {
    560           a.RunCopyElement(i, i + 1);  // Test element read/write.
    561         }
    562         if (Pipeline::SupportedTarget()) {  // verify.
    563           for (int j = 0; j < num_elements; j++) {
    564             E expect =
    565                 j == (i + 1) ? original_elements[i] : original_elements[j];
    566             CHECK_EQ(expect, a.GetElement(j));
    567           }
    568         }
    569       }
    570     }
    571   }
    572   // Test array copy.
    573   for (int tf = 0; tf < 2; tf++) {
    574     for (int tt = 0; tt < 2; tt++) {
    575       AccessTester<E> a(tf == 1, rep, original_elements, num);
    576       AccessTester<E> b(tt == 1, rep, original_elements, num);
    577       a.RunCopyElements(&b);
    578       if (Pipeline::SupportedTarget()) {  // verify.
    579         for (int i = 0; i < num_elements; i++) {
    580           CHECK_EQ(a.GetElement(i), b.GetElement(i));
    581         }
    582       }
    583     }
    584   }
    585 }
    586 
    587 
    588 TEST(RunAccessTests_uint8) {
    589   uint8_t data[] = {0x07, 0x16, 0x25, 0x34, 0x43, 0x99,
    590                     0xab, 0x78, 0x89, 0x19, 0x2b, 0x38};
    591   RunAccessTest<uint8_t>(kMachInt8, data, arraysize(data));
    592 }
    593 
    594 
    595 TEST(RunAccessTests_uint16) {
    596   uint16_t data[] = {0x071a, 0x162b, 0x253c, 0x344d, 0x435e, 0x7777};
    597   RunAccessTest<uint16_t>(kMachInt16, data, arraysize(data));
    598 }
    599 
    600 
    601 TEST(RunAccessTests_int32) {
    602   int32_t data[] = {-211, 211, 628347, 2000000000, -2000000000, -1, -100000034};
    603   RunAccessTest<int32_t>(kMachInt32, data, arraysize(data));
    604 }
    605 
    606 
    607 #define V8_2PART_INT64(a, b) (((static_cast<int64_t>(a) << 32) + 0x##b##u))
    608 
    609 
    610 TEST(RunAccessTests_int64) {
    611   if (kPointerSize != 8) return;
    612   int64_t data[] = {V8_2PART_INT64(0x10111213, 14151617),
    613                     V8_2PART_INT64(0x20212223, 24252627),
    614                     V8_2PART_INT64(0x30313233, 34353637),
    615                     V8_2PART_INT64(0xa0a1a2a3, a4a5a6a7),
    616                     V8_2PART_INT64(0xf0f1f2f3, f4f5f6f7)};
    617   RunAccessTest<int64_t>(kMachInt64, data, arraysize(data));
    618 }
    619 
    620 
    621 TEST(RunAccessTests_float64) {
    622   double data[] = {1.25, -1.25, 2.75, 11.0, 11100.8};
    623   RunAccessTest<double>(kMachFloat64, data, arraysize(data));
    624 }
    625 
    626 
    627 TEST(RunAccessTests_Smi) {
    628   Smi* data[] = {Smi::FromInt(-1),    Smi::FromInt(-9),
    629                  Smi::FromInt(0),     Smi::FromInt(666),
    630                  Smi::FromInt(77777), Smi::FromInt(Smi::kMaxValue)};
    631   RunAccessTest<Smi*>(kMachAnyTagged, data, arraysize(data));
    632 }
    633 
    634 
    635 // Fills in most of the nodes of the graph in order to make tests shorter.
    636 class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
    637  public:
    638   Typer typer;
    639   JSOperatorBuilder javascript;
    640   JSGraph jsgraph;
    641   Node* p0;
    642   Node* p1;
    643   Node* p2;
    644   Node* start;
    645   Node* end;
    646   Node* ret;
    647 
    648   explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
    649                         Type* p2_type = Type::None())
    650       : GraphAndBuilders(main_zone()),
    651         typer(main_zone()),
    652         javascript(main_zone()),
    653         jsgraph(graph(), common(), &javascript, &typer, machine()) {
    654     start = graph()->NewNode(common()->Start(2));
    655     graph()->SetStart(start);
    656     ret =
    657         graph()->NewNode(common()->Return(), jsgraph.Constant(0), start, start);
    658     end = graph()->NewNode(common()->End(), ret);
    659     graph()->SetEnd(end);
    660     p0 = graph()->NewNode(common()->Parameter(0), start);
    661     p1 = graph()->NewNode(common()->Parameter(1), start);
    662     p2 = graph()->NewNode(common()->Parameter(2), start);
    663     NodeProperties::SetBounds(p0, Bounds(p0_type));
    664     NodeProperties::SetBounds(p1, Bounds(p1_type));
    665     NodeProperties::SetBounds(p2, Bounds(p2_type));
    666   }
    667 
    668   void CheckLoweringBinop(IrOpcode::Value expected, const Operator* op) {
    669     Node* node = Return(graph()->NewNode(op, p0, p1));
    670     Lower();
    671     CHECK_EQ(expected, node->opcode());
    672   }
    673 
    674   void CheckLoweringTruncatedBinop(IrOpcode::Value expected, const Operator* op,
    675                                    const Operator* trunc) {
    676     Node* node = graph()->NewNode(op, p0, p1);
    677     Return(graph()->NewNode(trunc, node));
    678     Lower();
    679     CHECK_EQ(expected, node->opcode());
    680   }
    681 
    682   void Lower() {
    683     SimplifiedLowering lowering(&jsgraph);
    684     lowering.LowerAllNodes();
    685   }
    686 
    687   // Inserts the node as the return value of the graph.
    688   Node* Return(Node* node) {
    689     ret->ReplaceInput(0, node);
    690     return node;
    691   }
    692 
    693   // Inserts the node as the effect input to the return of the graph.
    694   void Effect(Node* node) { ret->ReplaceInput(1, node); }
    695 
    696   Node* ExampleWithOutput(MachineType type) {
    697     // TODO(titzer): use parameters with guaranteed representations.
    698     if (type & kTypeInt32) {
    699       return graph()->NewNode(machine()->Int32Add(), jsgraph.Int32Constant(1),
    700                               jsgraph.Int32Constant(1));
    701     } else if (type & kTypeUint32) {
    702       return graph()->NewNode(machine()->Word32Shr(), jsgraph.Int32Constant(1),
    703                               jsgraph.Int32Constant(1));
    704     } else if (type & kRepFloat64) {
    705       return graph()->NewNode(machine()->Float64Add(),
    706                               jsgraph.Float64Constant(1),
    707                               jsgraph.Float64Constant(1));
    708     } else if (type & kRepBit) {
    709       return graph()->NewNode(machine()->Word32Equal(),
    710                               jsgraph.Int32Constant(1),
    711                               jsgraph.Int32Constant(1));
    712     } else if (type & kRepWord64) {
    713       return graph()->NewNode(machine()->Int64Add(), Int64Constant(1),
    714                               Int64Constant(1));
    715     } else {
    716       CHECK(type & kRepTagged);
    717       return p0;
    718     }
    719   }
    720 
    721   Node* Use(Node* node, MachineType type) {
    722     if (type & kTypeInt32) {
    723       return graph()->NewNode(machine()->Int32LessThan(), node,
    724                               jsgraph.Int32Constant(1));
    725     } else if (type & kTypeUint32) {
    726       return graph()->NewNode(machine()->Uint32LessThan(), node,
    727                               jsgraph.Int32Constant(1));
    728     } else if (type & kRepFloat64) {
    729       return graph()->NewNode(machine()->Float64Add(), node,
    730                               jsgraph.Float64Constant(1));
    731     } else if (type & kRepWord64) {
    732       return graph()->NewNode(machine()->Int64LessThan(), node,
    733                               Int64Constant(1));
    734     } else {
    735       return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
    736                               jsgraph.TrueConstant());
    737     }
    738   }
    739 
    740   Node* Branch(Node* cond) {
    741     Node* br = graph()->NewNode(common()->Branch(), cond, start);
    742     Node* tb = graph()->NewNode(common()->IfTrue(), br);
    743     Node* fb = graph()->NewNode(common()->IfFalse(), br);
    744     Node* m = graph()->NewNode(common()->Merge(2), tb, fb);
    745     NodeProperties::ReplaceControlInput(ret, m);
    746     return br;
    747   }
    748 
    749   Node* Int64Constant(int64_t v) {
    750     return graph()->NewNode(common()->Int64Constant(v));
    751   }
    752 
    753   SimplifiedOperatorBuilder* simplified() { return &main_simplified_; }
    754   MachineOperatorBuilder* machine() { return &main_machine_; }
    755   CommonOperatorBuilder* common() { return &main_common_; }
    756   Graph* graph() { return main_graph_; }
    757 };
    758 
    759 
    760 TEST(LowerBooleanNot_bit_bit) {
    761   // BooleanNot(x: kRepBit) used as kRepBit
    762   TestingGraph t(Type::Boolean());
    763   Node* b = t.ExampleWithOutput(kRepBit);
    764   Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
    765   Node* use = t.Branch(inv);
    766   t.Lower();
    767   Node* cmp = use->InputAt(0);
    768   CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
    769   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
    770   Node* f = t.jsgraph.Int32Constant(0);
    771   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
    772 }
    773 
    774 
    775 TEST(LowerBooleanNot_bit_tagged) {
    776   // BooleanNot(x: kRepBit) used as kRepTagged
    777   TestingGraph t(Type::Boolean());
    778   Node* b = t.ExampleWithOutput(kRepBit);
    779   Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
    780   Node* use = t.Use(inv, kRepTagged);
    781   t.Return(use);
    782   t.Lower();
    783   CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
    784   Node* cmp = use->InputAt(0)->InputAt(0);
    785   CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
    786   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
    787   Node* f = t.jsgraph.Int32Constant(0);
    788   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
    789 }
    790 
    791 
    792 TEST(LowerBooleanNot_tagged_bit) {
    793   // BooleanNot(x: kRepTagged) used as kRepBit
    794   TestingGraph t(Type::Boolean());
    795   Node* b = t.p0;
    796   Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
    797   Node* use = t.Branch(inv);
    798   t.Lower();
    799   Node* cmp = use->InputAt(0);
    800   CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
    801   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
    802   Node* f = t.jsgraph.FalseConstant();
    803   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
    804 }
    805 
    806 
    807 TEST(LowerBooleanNot_tagged_tagged) {
    808   // BooleanNot(x: kRepTagged) used as kRepTagged
    809   TestingGraph t(Type::Boolean());
    810   Node* b = t.p0;
    811   Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
    812   Node* use = t.Use(inv, kRepTagged);
    813   t.Return(use);
    814   t.Lower();
    815   CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
    816   Node* cmp = use->InputAt(0)->InputAt(0);
    817   CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
    818   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
    819   Node* f = t.jsgraph.FalseConstant();
    820   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
    821 }
    822 
    823 
    824 TEST(LowerBooleanToNumber_bit_int32) {
    825   // BooleanToNumber(x: kRepBit) used as kMachInt32
    826   TestingGraph t(Type::Boolean());
    827   Node* b = t.ExampleWithOutput(kRepBit);
    828   Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
    829   Node* use = t.Use(cnv, kMachInt32);
    830   t.Return(use);
    831   t.Lower();
    832   CHECK_EQ(b, use->InputAt(0));
    833 }
    834 
    835 
    836 TEST(LowerBooleanToNumber_tagged_int32) {
    837   // BooleanToNumber(x: kRepTagged) used as kMachInt32
    838   TestingGraph t(Type::Boolean());
    839   Node* b = t.p0;
    840   Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
    841   Node* use = t.Use(cnv, kMachInt32);
    842   t.Return(use);
    843   t.Lower();
    844   CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
    845   CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
    846   Node* c = t.jsgraph.TrueConstant();
    847   CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
    848 }
    849 
    850 
    851 TEST(LowerBooleanToNumber_bit_tagged) {
    852   // BooleanToNumber(x: kRepBit) used as kMachAnyTagged
    853   TestingGraph t(Type::Boolean());
    854   Node* b = t.ExampleWithOutput(kRepBit);
    855   Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
    856   Node* use = t.Use(cnv, kMachAnyTagged);
    857   t.Return(use);
    858   t.Lower();
    859   CHECK_EQ(b, use->InputAt(0)->InputAt(0));
    860   CHECK_EQ(IrOpcode::kChangeInt32ToTagged, use->InputAt(0)->opcode());
    861 }
    862 
    863 
    864 TEST(LowerBooleanToNumber_tagged_tagged) {
    865   // BooleanToNumber(x: kRepTagged) used as kMachAnyTagged
    866   TestingGraph t(Type::Boolean());
    867   Node* b = t.p0;
    868   Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
    869   Node* use = t.Use(cnv, kMachAnyTagged);
    870   t.Return(use);
    871   t.Lower();
    872   CHECK_EQ(cnv, use->InputAt(0)->InputAt(0));
    873   CHECK_EQ(IrOpcode::kChangeInt32ToTagged, use->InputAt(0)->opcode());
    874   CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
    875   CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
    876   Node* c = t.jsgraph.TrueConstant();
    877   CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
    878 }
    879 
    880 
    881 static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(),
    882                              Type::Number(), Type::Any()};
    883 
    884 
    885 TEST(LowerNumberCmp_to_int32) {
    886   TestingGraph t(Type::Signed32(), Type::Signed32());
    887 
    888   t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual());
    889   t.CheckLoweringBinop(IrOpcode::kInt32LessThan,
    890                        t.simplified()->NumberLessThan());
    891   t.CheckLoweringBinop(IrOpcode::kInt32LessThanOrEqual,
    892                        t.simplified()->NumberLessThanOrEqual());
    893 }
    894 
    895 
    896 TEST(LowerNumberCmp_to_uint32) {
    897   TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
    898 
    899   t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual());
    900   t.CheckLoweringBinop(IrOpcode::kUint32LessThan,
    901                        t.simplified()->NumberLessThan());
    902   t.CheckLoweringBinop(IrOpcode::kUint32LessThanOrEqual,
    903                        t.simplified()->NumberLessThanOrEqual());
    904 }
    905 
    906 
    907 TEST(LowerNumberCmp_to_float64) {
    908   static Type* types[] = {Type::Number(), Type::Any()};
    909 
    910   for (size_t i = 0; i < arraysize(types); i++) {
    911     TestingGraph t(types[i], types[i]);
    912 
    913     t.CheckLoweringBinop(IrOpcode::kFloat64Equal,
    914                          t.simplified()->NumberEqual());
    915     t.CheckLoweringBinop(IrOpcode::kFloat64LessThan,
    916                          t.simplified()->NumberLessThan());
    917     t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual,
    918                          t.simplified()->NumberLessThanOrEqual());
    919   }
    920 }
    921 
    922 
    923 TEST(LowerNumberAddSub_to_int32) {
    924   TestingGraph t(Type::Signed32(), Type::Signed32());
    925   t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
    926                                 t.simplified()->NumberAdd(),
    927                                 t.simplified()->NumberToInt32());
    928   t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
    929                                 t.simplified()->NumberSubtract(),
    930                                 t.simplified()->NumberToInt32());
    931 }
    932 
    933 
    934 TEST(LowerNumberAddSub_to_uint32) {
    935   TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
    936   t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
    937                                 t.simplified()->NumberAdd(),
    938                                 t.simplified()->NumberToUint32());
    939   t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
    940                                 t.simplified()->NumberSubtract(),
    941                                 t.simplified()->NumberToUint32());
    942 }
    943 
    944 
    945 TEST(LowerNumberAddSub_to_float64) {
    946   for (size_t i = 0; i < arraysize(test_types); i++) {
    947     TestingGraph t(test_types[i], test_types[i]);
    948 
    949     t.CheckLoweringBinop(IrOpcode::kFloat64Add, t.simplified()->NumberAdd());
    950     t.CheckLoweringBinop(IrOpcode::kFloat64Sub,
    951                          t.simplified()->NumberSubtract());
    952   }
    953 }
    954 
    955 
    956 TEST(LowerNumberDivMod_to_float64) {
    957   for (size_t i = 0; i < arraysize(test_types); i++) {
    958     TestingGraph t(test_types[i], test_types[i]);
    959 
    960     t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
    961     t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
    962                          t.simplified()->NumberModulus());
    963   }
    964 }
    965 
    966 
    967 static void CheckChangeOf(IrOpcode::Value change, Node* of, Node* node) {
    968   CHECK_EQ(change, node->opcode());
    969   CHECK_EQ(of, node->InputAt(0));
    970 }
    971 
    972 
    973 TEST(LowerNumberToInt32_to_nop) {
    974   // NumberToInt32(x: kRepTagged | kTypeInt32) used as kRepTagged
    975   TestingGraph t(Type::Signed32());
    976   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
    977   Node* use = t.Use(trunc, kRepTagged);
    978   t.Return(use);
    979   t.Lower();
    980   CHECK_EQ(t.p0, use->InputAt(0));
    981 }
    982 
    983 
    984 TEST(LowerNumberToInt32_to_ChangeTaggedToFloat64) {
    985   // NumberToInt32(x: kRepTagged | kTypeInt32) used as kRepFloat64
    986   TestingGraph t(Type::Signed32());
    987   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
    988   Node* use = t.Use(trunc, kRepFloat64);
    989   t.Return(use);
    990   t.Lower();
    991   CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p0, use->InputAt(0));
    992 }
    993 
    994 
    995 TEST(LowerNumberToInt32_to_ChangeTaggedToInt32) {
    996   // NumberToInt32(x: kRepTagged | kTypeInt32) used as kRepWord32
    997   TestingGraph t(Type::Signed32());
    998   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
    999   Node* use = t.Use(trunc, kTypeInt32);
   1000   t.Return(use);
   1001   t.Lower();
   1002   CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p0, use->InputAt(0));
   1003 }
   1004 
   1005 
   1006 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
   1007   // NumberToInt32(x: kRepFloat64) used as kMachInt32
   1008   TestingGraph t(Type::Number());
   1009   Node* p0 = t.ExampleWithOutput(kMachFloat64);
   1010   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
   1011   Node* use = t.Use(trunc, kMachInt32);
   1012   t.Return(use);
   1013   t.Lower();
   1014   CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, p0, use->InputAt(0));
   1015 }
   1016 
   1017 
   1018 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32_with_change) {
   1019   // NumberToInt32(x: kTypeNumber | kRepTagged) used as kMachInt32
   1020   TestingGraph t(Type::Number());
   1021   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
   1022   Node* use = t.Use(trunc, kMachInt32);
   1023   t.Return(use);
   1024   t.Lower();
   1025   Node* node = use->InputAt(0);
   1026   CHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, node->opcode());
   1027   Node* of = node->InputAt(0);
   1028   CHECK_EQ(IrOpcode::kChangeTaggedToFloat64, of->opcode());
   1029   CHECK_EQ(t.p0, of->InputAt(0));
   1030 }
   1031 
   1032 
   1033 TEST(LowerNumberToInt32_to_ChangeFloat64ToTagged) {
   1034   // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepTagged
   1035 }
   1036 
   1037 
   1038 TEST(LowerNumberToInt32_to_ChangeFloat64ToInt32) {
   1039   // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepWord32
   1040   // | kTypeInt32
   1041 }
   1042 
   1043 
   1044 TEST(LowerNumberToUint32_to_nop) {
   1045   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepTagged
   1046   TestingGraph t(Type::Unsigned32());
   1047   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
   1048   Node* use = t.Use(trunc, kRepTagged);
   1049   t.Return(use);
   1050   t.Lower();
   1051   CHECK_EQ(t.p0, use->InputAt(0));
   1052 }
   1053 
   1054 
   1055 TEST(LowerNumberToUint32_to_ChangeTaggedToFloat64) {
   1056   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepWord32
   1057   TestingGraph t(Type::Unsigned32());
   1058   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
   1059   Node* use = t.Use(trunc, kRepFloat64);
   1060   t.Return(use);
   1061   t.Lower();
   1062   CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p0, use->InputAt(0));
   1063 }
   1064 
   1065 
   1066 TEST(LowerNumberToUint32_to_ChangeTaggedToUint32) {
   1067   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepWord32
   1068   TestingGraph t(Type::Unsigned32());
   1069   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
   1070   Node* use = t.Use(trunc, kTypeUint32);
   1071   t.Return(use);
   1072   t.Lower();
   1073   CheckChangeOf(IrOpcode::kChangeTaggedToUint32, t.p0, use->InputAt(0));
   1074 }
   1075 
   1076 
   1077 TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32) {
   1078   // NumberToUint32(x: kRepFloat64) used as kMachUint32
   1079   TestingGraph t(Type::Number());
   1080   Node* p0 = t.ExampleWithOutput(kMachFloat64);
   1081   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
   1082   Node* use = t.Use(trunc, kMachUint32);
   1083   t.Return(use);
   1084   t.Lower();
   1085   CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, p0, use->InputAt(0));
   1086 }
   1087 
   1088 
   1089 TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_with_change) {
   1090   // NumberToInt32(x: kTypeNumber | kRepTagged) used as kMachUint32
   1091   TestingGraph t(Type::Number());
   1092   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
   1093   Node* use = t.Use(trunc, kMachUint32);
   1094   t.Return(use);
   1095   t.Lower();
   1096   Node* node = use->InputAt(0);
   1097   CHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, node->opcode());
   1098   Node* of = node->InputAt(0);
   1099   CHECK_EQ(IrOpcode::kChangeTaggedToFloat64, of->opcode());
   1100   CHECK_EQ(t.p0, of->InputAt(0));
   1101 }
   1102 
   1103 
   1104 TEST(LowerNumberToUint32_to_ChangeFloat64ToTagged) {
   1105   // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
   1106   // kRepTagged
   1107 }
   1108 
   1109 
   1110 TEST(LowerNumberToUint32_to_ChangeFloat64ToUint32) {
   1111   // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
   1112   // kRepWord32
   1113 }
   1114 
   1115 
   1116 TEST(LowerNumberToUint32_to_TruncateFloat64ToUint32) {
   1117   // TODO(titzer): NumberToUint32(x: kRepFloat64) used as kRepWord32
   1118 }
   1119 
   1120 
   1121 TEST(LowerReferenceEqual_to_wordeq) {
   1122   TestingGraph t(Type::Any(), Type::Any());
   1123   IrOpcode::Value opcode =
   1124       static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode());
   1125   t.CheckLoweringBinop(opcode, t.simplified()->ReferenceEqual(Type::Any()));
   1126 }
   1127 
   1128 
   1129 TEST(LowerStringOps_to_call_and_compare) {
   1130   if (Pipeline::SupportedTarget()) {
   1131     // These tests need linkage for the calls.
   1132     TestingGraph t(Type::String(), Type::String());
   1133     IrOpcode::Value compare_eq =
   1134         static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode());
   1135     IrOpcode::Value compare_lt =
   1136         static_cast<IrOpcode::Value>(t.machine()->IntLessThan()->opcode());
   1137     IrOpcode::Value compare_le = static_cast<IrOpcode::Value>(
   1138         t.machine()->IntLessThanOrEqual()->opcode());
   1139     t.CheckLoweringBinop(compare_eq, t.simplified()->StringEqual());
   1140     t.CheckLoweringBinop(compare_lt, t.simplified()->StringLessThan());
   1141     t.CheckLoweringBinop(compare_le, t.simplified()->StringLessThanOrEqual());
   1142     t.CheckLoweringBinop(IrOpcode::kCall, t.simplified()->StringAdd());
   1143   }
   1144 }
   1145 
   1146 
   1147 void CheckChangeInsertion(IrOpcode::Value expected, MachineType from,
   1148                           MachineType to) {
   1149   TestingGraph t(Type::Any());
   1150   Node* in = t.ExampleWithOutput(from);
   1151   Node* use = t.Use(in, to);
   1152   t.Return(use);
   1153   t.Lower();
   1154   CHECK_EQ(expected, use->InputAt(0)->opcode());
   1155   CHECK_EQ(in, use->InputAt(0)->InputAt(0));
   1156 }
   1157 
   1158 
   1159 TEST(InsertBasicChanges) {
   1160   CheckChangeInsertion(IrOpcode::kChangeFloat64ToInt32, kRepFloat64,
   1161                        kTypeInt32);
   1162   CheckChangeInsertion(IrOpcode::kChangeFloat64ToUint32, kRepFloat64,
   1163                        kTypeUint32);
   1164   CheckChangeInsertion(IrOpcode::kChangeTaggedToInt32, kRepTagged, kTypeInt32);
   1165   CheckChangeInsertion(IrOpcode::kChangeTaggedToUint32, kRepTagged,
   1166                        kTypeUint32);
   1167 
   1168   CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, kRepFloat64,
   1169                        kRepTagged);
   1170   CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64, kRepTagged,
   1171                        kRepFloat64);
   1172 
   1173   CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, kTypeInt32,
   1174                        kRepFloat64);
   1175   CheckChangeInsertion(IrOpcode::kChangeInt32ToTagged, kTypeInt32, kRepTagged);
   1176 
   1177   CheckChangeInsertion(IrOpcode::kChangeUint32ToFloat64, kTypeUint32,
   1178                        kRepFloat64);
   1179   CheckChangeInsertion(IrOpcode::kChangeUint32ToTagged, kTypeUint32,
   1180                        kRepTagged);
   1181 }
   1182 
   1183 
   1184 static void CheckChangesAroundBinop(TestingGraph* t, const Operator* op,
   1185                                     IrOpcode::Value input_change,
   1186                                     IrOpcode::Value output_change) {
   1187   Node* binop = t->graph()->NewNode(op, t->p0, t->p1);
   1188   t->Return(binop);
   1189   t->Lower();
   1190   CHECK_EQ(input_change, binop->InputAt(0)->opcode());
   1191   CHECK_EQ(input_change, binop->InputAt(1)->opcode());
   1192   CHECK_EQ(t->p0, binop->InputAt(0)->InputAt(0));
   1193   CHECK_EQ(t->p1, binop->InputAt(1)->InputAt(0));
   1194   CHECK_EQ(output_change, t->ret->InputAt(0)->opcode());
   1195   CHECK_EQ(binop, t->ret->InputAt(0)->InputAt(0));
   1196 }
   1197 
   1198 
   1199 TEST(InsertChangesAroundInt32Binops) {
   1200   TestingGraph t(Type::Signed32(), Type::Signed32());
   1201 
   1202   const Operator* ops[] = {t.machine()->Int32Add(),  t.machine()->Int32Sub(),
   1203                            t.machine()->Int32Mul(),  t.machine()->Int32Div(),
   1204                            t.machine()->Int32Mod(),  t.machine()->Word32And(),
   1205                            t.machine()->Word32Or(),  t.machine()->Word32Xor(),
   1206                            t.machine()->Word32Shl(), t.machine()->Word32Sar()};
   1207 
   1208   for (size_t i = 0; i < arraysize(ops); i++) {
   1209     CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
   1210                             IrOpcode::kChangeInt32ToTagged);
   1211   }
   1212 }
   1213 
   1214 
   1215 TEST(InsertChangesAroundInt32Cmp) {
   1216   TestingGraph t(Type::Signed32(), Type::Signed32());
   1217 
   1218   const Operator* ops[] = {t.machine()->Int32LessThan(),
   1219                            t.machine()->Int32LessThanOrEqual()};
   1220 
   1221   for (size_t i = 0; i < arraysize(ops); i++) {
   1222     CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
   1223                             IrOpcode::kChangeBitToBool);
   1224   }
   1225 }
   1226 
   1227 
   1228 TEST(InsertChangesAroundUint32Cmp) {
   1229   TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
   1230 
   1231   const Operator* ops[] = {t.machine()->Uint32LessThan(),
   1232                            t.machine()->Uint32LessThanOrEqual()};
   1233 
   1234   for (size_t i = 0; i < arraysize(ops); i++) {
   1235     CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToUint32,
   1236                             IrOpcode::kChangeBitToBool);
   1237   }
   1238 }
   1239 
   1240 
   1241 TEST(InsertChangesAroundFloat64Binops) {
   1242   TestingGraph t(Type::Number(), Type::Number());
   1243 
   1244   const Operator* ops[] = {
   1245       t.machine()->Float64Add(), t.machine()->Float64Sub(),
   1246       t.machine()->Float64Mul(), t.machine()->Float64Div(),
   1247       t.machine()->Float64Mod(),
   1248   };
   1249 
   1250   for (size_t i = 0; i < arraysize(ops); i++) {
   1251     CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64,
   1252                             IrOpcode::kChangeFloat64ToTagged);
   1253   }
   1254 }
   1255 
   1256 
   1257 TEST(InsertChangesAroundFloat64Cmp) {
   1258   TestingGraph t(Type::Number(), Type::Number());
   1259 
   1260   const Operator* ops[] = {t.machine()->Float64Equal(),
   1261                            t.machine()->Float64LessThan(),
   1262                            t.machine()->Float64LessThanOrEqual()};
   1263 
   1264   for (size_t i = 0; i < arraysize(ops); i++) {
   1265     CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64,
   1266                             IrOpcode::kChangeBitToBool);
   1267   }
   1268 }
   1269 
   1270 
   1271 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
   1272   Int32Matcher index = Int32Matcher(load_or_store->InputAt(1));
   1273   CHECK(index.Is(access.offset - access.tag()));
   1274 }
   1275 
   1276 
   1277 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
   1278   Int32BinopMatcher index(load_or_store->InputAt(1));
   1279   CHECK_EQ(IrOpcode::kInt32Add, index.node()->opcode());
   1280   CHECK(index.right().Is(access.header_size - access.tag()));
   1281 
   1282   int element_size = ElementSizeOf(access.machine_type);
   1283 
   1284   if (element_size != 1) {
   1285     Int32BinopMatcher mul(index.left().node());
   1286     CHECK_EQ(IrOpcode::kInt32Mul, mul.node()->opcode());
   1287     CHECK(mul.right().Is(element_size));
   1288     return mul.left().node();
   1289   } else {
   1290     return index.left().node();
   1291   }
   1292 }
   1293 
   1294 
   1295 static const MachineType machine_reps[] = {
   1296     kRepBit,    kMachInt8,    kMachInt16,    kMachInt32,
   1297     kMachInt64, kMachFloat64, kMachAnyTagged};
   1298 
   1299 
   1300 TEST(LowerLoadField_to_load) {
   1301   TestingGraph t(Type::Any(), Type::Signed32());
   1302 
   1303   for (size_t i = 0; i < arraysize(machine_reps); i++) {
   1304     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1305                           Handle<Name>::null(), Type::Any(), machine_reps[i]};
   1306 
   1307     Node* load =
   1308         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
   1309     Node* use = t.Use(load, machine_reps[i]);
   1310     t.Return(use);
   1311     t.Lower();
   1312     CHECK_EQ(IrOpcode::kLoad, load->opcode());
   1313     CHECK_EQ(t.p0, load->InputAt(0));
   1314     CheckFieldAccessArithmetic(access, load);
   1315 
   1316     MachineType rep = OpParameter<MachineType>(load);
   1317     CHECK_EQ(machine_reps[i], rep);
   1318   }
   1319 }
   1320 
   1321 
   1322 TEST(LowerStoreField_to_store) {
   1323   TestingGraph t(Type::Any(), Type::Signed32());
   1324 
   1325   for (size_t i = 0; i < arraysize(machine_reps); i++) {
   1326     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1327                           Handle<Name>::null(), Type::Any(), machine_reps[i]};
   1328 
   1329 
   1330     Node* val = t.ExampleWithOutput(machine_reps[i]);
   1331     Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
   1332                                      val, t.start, t.start);
   1333     t.Effect(store);
   1334     t.Lower();
   1335     CHECK_EQ(IrOpcode::kStore, store->opcode());
   1336     CHECK_EQ(val, store->InputAt(2));
   1337     CheckFieldAccessArithmetic(access, store);
   1338 
   1339     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
   1340     if (machine_reps[i] & kRepTagged) {
   1341       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
   1342     }
   1343     CHECK_EQ(machine_reps[i], rep.machine_type());
   1344   }
   1345 }
   1346 
   1347 
   1348 TEST(LowerLoadElement_to_load) {
   1349   TestingGraph t(Type::Any(), Type::Signed32());
   1350 
   1351   for (size_t i = 0; i < arraysize(machine_reps); i++) {
   1352     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1353                             Type::Any(), machine_reps[i]};
   1354 
   1355     Node* load =
   1356         t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
   1357                            t.jsgraph.Int32Constant(1024), t.start);
   1358     Node* use = t.Use(load, machine_reps[i]);
   1359     t.Return(use);
   1360     t.Lower();
   1361     CHECK_EQ(IrOpcode::kLoad, load->opcode());
   1362     CHECK_EQ(t.p0, load->InputAt(0));
   1363     CheckElementAccessArithmetic(access, load);
   1364 
   1365     MachineType rep = OpParameter<MachineType>(load);
   1366     CHECK_EQ(machine_reps[i], rep);
   1367   }
   1368 }
   1369 
   1370 
   1371 TEST(LowerStoreElement_to_store) {
   1372   TestingGraph t(Type::Any(), Type::Signed32());
   1373 
   1374   for (size_t i = 0; i < arraysize(machine_reps); i++) {
   1375     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1376                             Type::Any(), machine_reps[i]};
   1377 
   1378     Node* val = t.ExampleWithOutput(machine_reps[i]);
   1379     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
   1380                                      t.p1, t.jsgraph.Int32Constant(1024), val,
   1381                                      t.start, t.start);
   1382     t.Effect(store);
   1383     t.Lower();
   1384     CHECK_EQ(IrOpcode::kStore, store->opcode());
   1385     CHECK_EQ(val, store->InputAt(2));
   1386     CheckElementAccessArithmetic(access, store);
   1387 
   1388     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
   1389     if (machine_reps[i] & kRepTagged) {
   1390       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
   1391     }
   1392     CHECK_EQ(machine_reps[i], rep.machine_type());
   1393   }
   1394 }
   1395 
   1396 
   1397 TEST(InsertChangeForLoadElementIndex) {
   1398   // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   1399   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
   1400   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   1401   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
   1402                           kMachAnyTagged};
   1403 
   1404   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
   1405                                   t.p1, t.p2, t.start);
   1406   t.Return(load);
   1407   t.Lower();
   1408   CHECK_EQ(IrOpcode::kLoad, load->opcode());
   1409   CHECK_EQ(t.p0, load->InputAt(0));
   1410 
   1411   Node* index = CheckElementAccessArithmetic(access, load);
   1412   CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index);
   1413 }
   1414 
   1415 
   1416 TEST(InsertChangeForStoreElementIndex) {
   1417   // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   1418   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
   1419   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   1420   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
   1421                           kMachAnyTagged};
   1422 
   1423   Node* store =
   1424       t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
   1425                          t.jsgraph.TrueConstant(), t.start, t.start);
   1426   t.Effect(store);
   1427   t.Lower();
   1428   CHECK_EQ(IrOpcode::kStore, store->opcode());
   1429   CHECK_EQ(t.p0, store->InputAt(0));
   1430 
   1431   Node* index = CheckElementAccessArithmetic(access, store);
   1432   CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index);
   1433 }
   1434 
   1435 
   1436 TEST(InsertChangeForLoadElement) {
   1437   // TODO(titzer): test all load/store representation change insertions.
   1438   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   1439   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
   1440                           kMachFloat64};
   1441 
   1442   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
   1443                                   t.p1, t.p1, t.start);
   1444   t.Return(load);
   1445   t.Lower();
   1446   CHECK_EQ(IrOpcode::kLoad, load->opcode());
   1447   CHECK_EQ(t.p0, load->InputAt(0));
   1448   CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
   1449 }
   1450 
   1451 
   1452 TEST(InsertChangeForLoadField) {
   1453   // TODO(titzer): test all load/store representation change insertions.
   1454   TestingGraph t(Type::Any(), Type::Signed32());
   1455   FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1456                         Handle<Name>::null(), Type::Any(), kMachFloat64};
   1457 
   1458   Node* load =
   1459       t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
   1460   t.Return(load);
   1461   t.Lower();
   1462   CHECK_EQ(IrOpcode::kLoad, load->opcode());
   1463   CHECK_EQ(t.p0, load->InputAt(0));
   1464   CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
   1465 }
   1466 
   1467 
   1468 TEST(InsertChangeForStoreElement) {
   1469   // TODO(titzer): test all load/store representation change insertions.
   1470   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   1471   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
   1472                           kMachFloat64};
   1473 
   1474   Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
   1475                                    t.jsgraph.Int32Constant(0), t.p2, t.p1,
   1476                                    t.start, t.start);
   1477   t.Effect(store);
   1478   t.Lower();
   1479 
   1480   CHECK_EQ(IrOpcode::kStore, store->opcode());
   1481   CHECK_EQ(t.p0, store->InputAt(0));
   1482   CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
   1483 }
   1484 
   1485 
   1486 TEST(InsertChangeForStoreField) {
   1487   // TODO(titzer): test all load/store representation change insertions.
   1488   TestingGraph t(Type::Any(), Type::Signed32());
   1489   FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1490                         Handle<Name>::null(), Type::Any(), kMachFloat64};
   1491 
   1492   Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
   1493                                    t.p1, t.start, t.start);
   1494   t.Effect(store);
   1495   t.Lower();
   1496 
   1497   CHECK_EQ(IrOpcode::kStore, store->opcode());
   1498   CHECK_EQ(t.p0, store->InputAt(0));
   1499   CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
   1500 }
   1501 
   1502 
   1503 TEST(UpdatePhi) {
   1504   TestingGraph t(Type::Any(), Type::Signed32());
   1505   static const MachineType kMachineTypes[] = {kMachInt32, kMachUint32,
   1506                                               kMachFloat64};
   1507 
   1508   for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
   1509     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1510                           Handle<Name>::null(), Type::Any(), kMachineTypes[i]};
   1511 
   1512     Node* load0 =
   1513         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
   1514     Node* load1 =
   1515         t.graph()->NewNode(t.simplified()->LoadField(access), t.p1, t.start);
   1516     Node* phi = t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), load0,
   1517                                    load1, t.start);
   1518     t.Return(t.Use(phi, kMachineTypes[i]));
   1519     t.Lower();
   1520 
   1521     CHECK_EQ(IrOpcode::kPhi, phi->opcode());
   1522     CHECK_EQ(RepresentationOf(kMachineTypes[i]),
   1523              RepresentationOf(OpParameter<MachineType>(phi)));
   1524   }
   1525 }
   1526 
   1527 
   1528 // TODO(titzer): this tests current behavior of assuming an implicit
   1529 // representation change in loading float32s. Fix when float32 is fully
   1530 // supported.
   1531 TEST(ImplicitFloat32ToFloat64InLoads) {
   1532   TestingGraph t(Type::Any());
   1533 
   1534   FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1535                         Handle<Name>::null(), Type::Any(), kMachFloat32};
   1536 
   1537   Node* load =
   1538       t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
   1539   t.Return(load);
   1540   t.Lower();
   1541   CHECK_EQ(IrOpcode::kLoad, load->opcode());
   1542   CHECK_EQ(t.p0, load->InputAt(0));
   1543   CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
   1544 }
   1545 
   1546 
   1547 TEST(ImplicitFloat64ToFloat32InStores) {
   1548   TestingGraph t(Type::Any(), Type::Signed32());
   1549   FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
   1550                         Handle<Name>::null(), Type::Any(), kMachFloat32};
   1551 
   1552   Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
   1553                                    t.p1, t.start, t.start);
   1554   t.Effect(store);
   1555   t.Lower();
   1556 
   1557   CHECK_EQ(IrOpcode::kStore, store->opcode());
   1558   CHECK_EQ(t.p0, store->InputAt(0));
   1559   CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
   1560 }
   1561