Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / compiler / test-simplified-lowering.cc
index 96fb965..5ddc10d 100644 (file)
@@ -5,8 +5,10 @@
 #include <limits>
 
 #include "src/compiler/access-builder.h"
+#include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
 #include "src/compiler/generic-node-inl.h"
+#include "src/compiler/graph-reducer.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
@@ -35,10 +37,9 @@ class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> {
                            MachineType p3 = kMachNone,
                            MachineType p4 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4),
-        typer(this->zone()),
+        typer(this->graph(), MaybeHandle<Context>()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
         lowering(&jsgraph) {}
 
   Typer typer;
@@ -48,16 +49,40 @@ class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> {
 
   void LowerAllNodes() {
     this->End();
+    typer.Run();
     lowering.LowerAllNodes();
   }
 
+  void LowerAllNodesAndLowerChanges() {
+    this->End();
+    typer.Run();
+    lowering.LowerAllNodes();
+
+    Zone* zone = this->zone();
+    CompilationInfo info(zone->isolate(), zone);
+    Linkage linkage(
+        zone, Linkage::GetSimplifiedCDescriptor(zone, this->machine_sig_));
+    ChangeLowering lowering(&jsgraph, &linkage);
+    GraphReducer reducer(this->graph());
+    reducer.AddReducer(&lowering);
+    reducer.ReduceGraph();
+    Verifier::Run(this->graph());
+  }
+
+  void CheckNumberCall(double expected, double input) {
+    // TODO(titzer): make calls to NewNumber work in cctests.
+    if (expected <= Smi::kMinValue) return;
+    if (expected >= Smi::kMaxValue) return;
+    Handle<Object> num = factory()->NewNumber(input);
+    Object* result = this->Call(*num);
+    CHECK(factory()->NewNumber(expected)->SameValue(result));
+  }
+
   Factory* factory() { return this->isolate()->factory(); }
   Heap* heap() { return this->isolate()->heap(); }
 };
 
 
-#ifndef V8_TARGET_ARCH_ARM64
-// TODO(titzer): these result in a stub call that doesn't work on ARM64.
 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
 // TODO(titzer): test tagged representation for input to NumberToInt32.
 TEST(RunNumberToInt32_float64) {
@@ -68,6 +93,7 @@ TEST(RunNumberToInt32_float64) {
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToInt32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
                        kMachInt32};
@@ -96,6 +122,7 @@ TEST(RunNumberToUint32_float64) {
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToUint32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
                        kMachUint32};
@@ -113,7 +140,6 @@ TEST(RunNumberToUint32_float64) {
     }
   }
 }
-#endif
 
 
 // Create a simple JSObject with a unique map.
@@ -235,7 +261,7 @@ TEST(RunLoadStoreArrayBuffer) {
   const int index = 12;
   const int array_length = 2 * index;
   ElementAccess buffer_access =
-      AccessBuilder::ForBackingStoreElement(kMachInt8);
+      AccessBuilder::ForTypedArrayElement(v8::kExternalInt8Array, true);
   Node* backing_store = t.LoadField(
       AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
   Node* load =
@@ -325,8 +351,8 @@ TEST(RunLoadElementFromUntaggedBase) {
   for (size_t i = 0; i < arraysize(smis); i++) {    // for header sizes
     for (size_t j = 0; (i + j) < arraysize(smis); j++) {  // for element index
       int offset = static_cast<int>(i * sizeof(Smi*));
-      ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
-                              kMachAnyTagged};
+      ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset,
+                              Type::Integral32(), kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t;
       Node* load = t.LoadElement(
@@ -354,8 +380,8 @@ TEST(RunStoreElementFromUntaggedBase) {
   for (size_t i = 0; i < arraysize(smis); i++) {    // for header sizes
     for (size_t j = 0; (i + j) < arraysize(smis); j++) {  // for element index
       int offset = static_cast<int>(i * sizeof(Smi*));
-      ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
-                              kMachAnyTagged};
+      ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset,
+                              Type::Integral32(), kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
       Node* p0 = t.Parameter(0);
@@ -517,9 +543,9 @@ class AccessTester : public HandleAndZoneScope {
 
  private:
   ElementAccess GetElementAccess() {
-    ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase,
-                            tagged ? FixedArrayBase::kHeaderSize : 0,
-                            Type::Any(), rep};
+    ElementAccess access = {
+        kNoBoundsCheck, tagged ? kTaggedBase : kUntaggedBase,
+        tagged ? FixedArrayBase::kHeaderSize : 0, Type::Any(), rep};
     return access;
   }
 
@@ -648,9 +674,9 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
   explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
                         Type* p2_type = Type::None())
       : GraphAndBuilders(main_zone()),
-        typer(main_zone()),
+        typer(graph(), MaybeHandle<Context>()),
         javascript(main_zone()),
-        jsgraph(graph(), common(), &javascript, &typer, machine()) {
+        jsgraph(graph(), common(), &javascript, machine()) {
     start = graph()->NewNode(common()->Start(2));
     graph()->SetStart(start);
     ret =
@@ -660,6 +686,7 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
     p0 = graph()->NewNode(common()->Parameter(0), start);
     p1 = graph()->NewNode(common()->Parameter(1), start);
     p2 = graph()->NewNode(common()->Parameter(2), start);
+    typer.Run();
     NodeProperties::SetBounds(p0, Bounds(p0_type));
     NodeProperties::SetBounds(p1, Bounds(p1_type));
     NodeProperties::SetBounds(p2, Bounds(p2_type));
@@ -680,8 +707,7 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
   }
 
   void Lower() {
-    SimplifiedLowering lowering(&jsgraph);
-    lowering.LowerAllNodes();
+    SimplifiedLowering(&jsgraph).LowerAllNodes();
   }
 
   // Inserts the node as the return value of the graph.
@@ -765,7 +791,7 @@ TEST(LowerBooleanNot_bit_bit) {
   Node* use = t.Branch(inv);
   t.Lower();
   Node* cmp = use->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -782,7 +808,7 @@ TEST(LowerBooleanNot_bit_tagged) {
   t.Lower();
   CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
   Node* cmp = use->InputAt(0)->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -921,24 +947,50 @@ TEST(LowerNumberCmp_to_float64) {
 
 
 TEST(LowerNumberAddSub_to_int32) {
-  TestingGraph t(Type::Signed32(), Type::Signed32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToInt32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToInt32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToInt32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToInt32());
+    }
+  }
 }
 
 
 TEST(LowerNumberAddSub_to_uint32) {
-  TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToUint32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToUint32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToUint32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToUint32());
+    }
+  }
 }
 
 
@@ -958,8 +1010,10 @@ TEST(LowerNumberDivMod_to_float64) {
     TestingGraph t(test_types[i], test_types[i]);
 
     t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
-    t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
-                         t.simplified()->NumberModulus());
+    if (!test_types[i]->Is(Type::Unsigned32())) {
+      t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
+                           t.simplified()->NumberModulus());
+    }
   }
 }
 
@@ -1007,6 +1061,8 @@ TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
   // NumberToInt32(x: kRepFloat64) used as kMachInt32
   TestingGraph t(Type::Number());
   Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  // TODO(titzer): run the typer here, or attach machine type to param.
+  NodeProperties::SetBounds(p0, Bounds(Type::Number()));
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
   Node* use = t.Use(trunc, kMachInt32);
   t.Return(use);
@@ -1078,6 +1134,8 @@ TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32) {
   // NumberToUint32(x: kRepFloat64) used as kMachUint32
   TestingGraph t(Type::Number());
   Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  // TODO(titzer): run the typer here, or attach machine type to param.
+  NodeProperties::SetBounds(p0, Bounds(Type::Number()));
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
   Node* use = t.Use(trunc, kMachUint32);
   t.Return(use);
@@ -1268,45 +1326,54 @@ TEST(InsertChangesAroundFloat64Cmp) {
 }
 
 
+namespace {
+
 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
-  Int32Matcher index = Int32Matcher(load_or_store->InputAt(1));
-  CHECK(index.Is(access.offset - access.tag()));
+  IntPtrMatcher mindex(load_or_store->InputAt(1));
+  CHECK(mindex.Is(access.offset - access.tag()));
 }
 
 
 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
-  Int32BinopMatcher index(load_or_store->InputAt(1));
-  CHECK_EQ(IrOpcode::kInt32Add, index.node()->opcode());
-  CHECK(index.right().Is(access.header_size - access.tag()));
+  Node* index = load_or_store->InputAt(1);
+  if (kPointerSize == 8) {
+    CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode());
+    index = index->InputAt(0);
+  }
 
-  int element_size = ElementSizeOf(access.machine_type);
+  Int32BinopMatcher mindex(index);
+  CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode());
+  CHECK(mindex.right().Is(access.header_size - access.tag()));
 
-  if (element_size != 1) {
-    Int32BinopMatcher mul(index.left().node());
-    CHECK_EQ(IrOpcode::kInt32Mul, mul.node()->opcode());
-    CHECK(mul.right().Is(element_size));
-    return mul.left().node();
+  const int element_size_shift = ElementSizeLog2Of(access.machine_type);
+  if (element_size_shift) {
+    Int32BinopMatcher shl(mindex.left().node());
+    CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode());
+    CHECK(shl.right().Is(element_size_shift));
+    return shl.left().node();
   } else {
-    return index.left().node();
+    return mindex.left().node();
   }
 }
 
 
-static const MachineType machine_reps[] = {
-    kRepBit,    kMachInt8,    kMachInt16,    kMachInt32,
-    kMachInt64, kMachFloat64, kMachAnyTagged};
+const MachineType kMachineReps[] = {kRepBit,       kMachInt8,  kMachInt16,
+                                    kMachInt32,    kMachInt64, kMachFloat64,
+                                    kMachAnyTagged};
+
+}  // namespace
 
 
 TEST(LowerLoadField_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
     Node* load =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1314,7 +1381,7 @@ TEST(LowerLoadField_to_load) {
     CheckFieldAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1322,12 +1389,12 @@ TEST(LowerLoadField_to_load) {
 TEST(LowerStoreField_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
                                      val, t.start, t.start);
     t.Effect(store);
@@ -1337,10 +1404,10 @@ TEST(LowerStoreField_to_store) {
     CheckFieldAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1348,14 +1415,15 @@ TEST(LowerStoreField_to_store) {
 TEST(LowerLoadElement_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
-    ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
+    ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                            FixedArrayBase::kHeaderSize, Type::Any(),
+                            kMachineReps[i]};
 
     Node* load =
         t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
-                           t.jsgraph.Int32Constant(1024), t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+                           t.jsgraph.Int32Constant(1024), t.start, t.start);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1363,7 +1431,7 @@ TEST(LowerLoadElement_to_load) {
     CheckElementAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1371,11 +1439,12 @@ TEST(LowerLoadElement_to_load) {
 TEST(LowerStoreElement_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
-    ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
+    ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                            FixedArrayBase::kHeaderSize, Type::Any(),
+                            kMachineReps[i]};
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
                                      t.p1, t.jsgraph.Int32Constant(1024), val,
                                      t.start, t.start);
@@ -1386,10 +1455,10 @@ TEST(LowerStoreElement_to_store) {
     CheckElementAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1398,11 +1467,12 @@ TEST(InsertChangeForLoadElementIndex) {
   // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p2, t.start);
+                                  t.p1, t.p2, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1417,7 +1487,8 @@ TEST(InsertChangeForStoreElementIndex) {
   // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* store =
@@ -1436,11 +1507,12 @@ TEST(InsertChangeForStoreElementIndex) {
 TEST(InsertChangeForLoadElement) {
   // TODO(titzer): test all load/store representation change insertions.
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p1, t.start);
+                                  t.p1, t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1468,7 +1540,8 @@ TEST(InsertChangeForLoadField) {
 TEST(InsertChangeForStoreElement) {
   // TODO(titzer): test all load/store representation change insertions.
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
   Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
@@ -1504,10 +1577,11 @@ TEST(UpdatePhi) {
   TestingGraph t(Type::Any(), Type::Signed32());
   static const MachineType kMachineTypes[] = {kMachInt32, kMachUint32,
                                               kMachFloat64};
+  Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()};
 
   for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), kMachineTypes[i]};
+                          Handle<Name>::null(), kTypes[i], kMachineTypes[i]};
 
     Node* load0 =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
@@ -1525,36 +1599,409 @@ TEST(UpdatePhi) {
 }
 
 
-// TODO(titzer): this tests current behavior of assuming an implicit
-// representation change in loading float32s. Fix when float32 is fully
-// supported.
-TEST(ImplicitFloat32ToFloat64InLoads) {
-  TestingGraph t(Type::Any());
+TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToInt32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
+  Node* trunc = t.NumberToInt32(div);
+  t.Return(trunc);
 
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
 
-  Node* load =
-      t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-  t.Return(load);
-  t.Lower();
-  CHECK_EQ(IrOpcode::kLoad, load->opcode());
-  CHECK_EQ(t.p0, load->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
+    FOR_INT32_INPUTS(i) {
+      int32_t x = 0 - *i;
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
 }
 
 
-TEST(ImplicitFloat64ToFloat32InStores) {
-  TestingGraph t(Type::Any(), Type::Signed32());
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+TEST(NumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
-                                   t.p1, t.start, t.start);
-  t.Effect(store);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+    t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mul, mul->opcode());
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToUint32) {
+  uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToUint32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberDivide_2_TruncatingToUint32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToUint32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
+  Node* trunc = t.NumberToUint32(div);
+  t.Return(trunc);
+
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
+
+    FOR_UINT32_INPUTS(i) {
+      uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
+}
+
+
+TEST(NumberMultiply_ConstantOutOfRange) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(1000000023);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+  t.Return(trunc);
   t.Lower();
 
-  CHECK_EQ(IrOpcode::kStore, store->opcode());
-  CHECK_EQ(t.p0, store->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberMultiply_NonTruncating) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(111);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  t.Return(mul);
+  t.Lower();
+
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToUint32) {
+  uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i / k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_BadConstants) {
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(-1);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
+  }
+
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+
+  {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* use = t.Use(mod, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
+    Node* ret = t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToUint32) {
+  uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mod =
+        t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i % k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_Int32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    t.Return(mod);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode());  // Pesky -0 behavior.
+  }
+}
+
+
+TEST(NumberModulus_Uint32) {
+  const double kConstants[] = {2, 100, 1000, 1024, 2048};
+  const MachineType kTypes[] = {kMachInt32, kMachUint32};
+
+  for (auto const type : kTypes) {
+    for (auto const c : kConstants) {
+      TestingGraph t(Type::Unsigned32());
+      Node* k = t.jsgraph.Constant(c);
+      Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+      Node* use = t.Use(mod, type);
+      t.Return(use);
+      t.Lower();
+
+      CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode());
+    }
+  }
+}
+
+
+TEST(PhiRepresentation) {
+  HandleAndZoneScope scope;
+  Zone* z = scope.main_zone();
+
+  Factory* f = z->isolate()->factory();
+  Handle<Object> range_min = f->NewNumber(-1e13);
+  Handle<Object> range_max = f->NewNumber(1e+15);
+  Type* range = Type::Range(range_min, range_max, z);
+
+  struct TestData {
+    Type* arg1;
+    Type* arg2;
+    MachineType use;
+    MachineTypeUnion expected;
+  };
+
+  TestData test_data[] = {
+      {Type::Signed32(), Type::Unsigned32(), kMachInt32,
+       kRepWord32 | kTypeNumber},
+      {range, range, kMachUint32, kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Signed32(), kMachInt32, kMachInt32},
+      {Type::Unsigned32(), Type::Unsigned32(), kMachInt32, kMachUint32},
+      {Type::Number(), Type::Signed32(), kMachInt32, kMachFloat64},
+      {Type::Signed32(), Type::String(), kMachInt32, kMachAnyTagged}};
+
+  for (auto const d : test_data) {
+    TestingGraph t(d.arg1, d.arg2, Type::Boolean());
+
+    Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start);
+    Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br);
+    Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br);
+    Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb);
+
+    Node* phi =
+        t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), t.p0, t.p1, m);
+
+    Bounds phi_bounds = Bounds::Either(Bounds(d.arg1), Bounds(d.arg2), z);
+    NodeProperties::SetBounds(phi, phi_bounds);
+
+    Node* use = t.Use(phi, d.use);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(d.expected, OpParameter<MachineType>(phi));
+  }
 }