Fix bugs in simplified lowering relating to int32/uint32 signs.
authortitzer@chromium.org <titzer@chromium.org>
Mon, 10 Nov 2014 14:28:09 +0000 (14:28 +0000)
committertitzer@chromium.org <titzer@chromium.org>
Mon, 10 Nov 2014 14:28:42 +0000 (14:28 +0000)
Lowering of NumberToUint32 and NumberToInt32 was not correctly accounting for the sign of the input and the sign of the output, emitting the wrong representation changes.

Along the way, I've found cases where MachineOperatorBuilder would break if fed a machine type for loads or stores that was not cached, requiring MachineOperatorBuilder to take zone to allocate operators for these cases.

R=bmeurer@chromium.org, jarin@chromium.org
BUG=

Review URL: https://codereview.chromium.org/714613002

Cr-Commit-Position: refs/heads/master@{#25247}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25247 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

23 files changed:
src/compiler/basic-block-instrumentor.cc
src/compiler/machine-operator.cc
src/compiler/machine-operator.h
src/compiler/pipeline.cc
src/compiler/raw-machine-assembler.cc
src/compiler/simplified-lowering.cc
src/compiler/typer.cc
test/cctest/compiler/graph-builder-tester.h
test/cctest/compiler/test-instruction.cc
test/cctest/compiler/test-js-constant-cache.cc
test/cctest/compiler/test-js-context-specialization.cc
test/cctest/compiler/test-js-typed-lowering.cc
test/cctest/compiler/test-machine-operator-reducer.cc
test/cctest/compiler/test-schedule.cc
test/cctest/compiler/test-scheduler.cc
test/cctest/compiler/test-simplified-lowering.cc
test/mjsunit/mod-range.js [new file with mode: 0644]
test/unittests/compiler/change-lowering-unittest.cc
test/unittests/compiler/js-builtin-reducer-unittest.cc
test/unittests/compiler/js-typed-lowering-unittest.cc
test/unittests/compiler/machine-operator-reducer-unittest.cc
test/unittests/compiler/node-matchers-unittest.cc
test/unittests/compiler/simplified-operator-reducer-unittest.cc

index 708ec49..59bb7f4 100644 (file)
@@ -69,7 +69,7 @@ BasicBlockProfiler::Data* BasicBlockInstrumentor::Instrument(
   CommonOperatorBuilder common(graph->zone());
   Node* zero = graph->NewNode(common.Int32Constant(0));
   Node* one = graph->NewNode(common.Int32Constant(1));
-  MachineOperatorBuilder machine;
+  MachineOperatorBuilder machine(graph->zone());
   BasicBlockVector* blocks = schedule->rpo_order();
   size_t block_number = 0;
   for (BasicBlockVector::iterator it = blocks->begin(); block_number < n_blocks;
index 2ea1bf3..83459f7 100644 (file)
@@ -7,6 +7,8 @@
 #include "src/base/lazy-instance.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
+#include "src/v8.h"
+#include "src/zone-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -196,8 +198,9 @@ static base::LazyInstance<MachineOperatorGlobalCache>::type kCache =
     LAZY_INSTANCE_INITIALIZER;
 
 
-MachineOperatorBuilder::MachineOperatorBuilder(MachineType word, Flags flags)
-    : cache_(kCache.Get()), word_(word), flags_(flags) {
+MachineOperatorBuilder::MachineOperatorBuilder(Zone* zone, MachineType word,
+                                               Flags flags)
+    : zone_(zone), cache_(kCache.Get()), word_(word), flags_(flags) {
   DCHECK(word == kRepWord32 || word == kRepWord64);
 }
 
@@ -220,8 +223,10 @@ const Operator* MachineOperatorBuilder::Load(LoadRepresentation rep) {
     default:
       break;
   }
-  UNREACHABLE();
-  return NULL;
+  // Uncached.
+  return new (zone_) Operator1<LoadRepresentation>(  // --
+      IrOpcode::kLoad, Operator::kNoThrow | Operator::kNoWrite, "Load", 2, 1, 1,
+      1, 1, 0, rep);
 }
 
 
@@ -242,8 +247,10 @@ const Operator* MachineOperatorBuilder::Store(StoreRepresentation rep) {
     default:
       break;
   }
-  UNREACHABLE();
-  return NULL;
+  // Uncached.
+  return new (zone_) Operator1<StoreRepresentation>(  // --
+      IrOpcode::kStore, Operator::kNoRead | Operator::kNoThrow, "Store", 3, 1,
+      1, 0, 1, 0, rep);
 }
 }  // namespace compiler
 }  // namespace internal
index 979a887..8c0d11a 100644 (file)
@@ -73,7 +73,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   };
   typedef base::Flags<Flag, unsigned> Flags;
 
-  explicit MachineOperatorBuilder(MachineType word = kMachPtr,
+  explicit MachineOperatorBuilder(Zone* zone, MachineType word = kMachPtr,
                                   Flags supportedOperators = kNoFlags);
 
   const Operator* Word32And();
@@ -211,6 +211,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
 #undef PSEUDO_OP_LIST
 
  private:
+  Zone* zone_;
   const MachineOperatorGlobalCache& cache_;
   const MachineType word_;
   const Flags flags_;
index e116f97..5832905 100644 (file)
@@ -53,7 +53,8 @@ class PipelineData {
         graph_(new (graph_zone()) Graph(graph_zone())),
         source_positions_(new SourcePositionTable(graph())),
         machine_(new (graph_zone()) MachineOperatorBuilder(
-            kMachPtr, InstructionSelector::SupportedMachineOperatorFlags())),
+            graph_zone(), kMachPtr,
+            InstructionSelector::SupportedMachineOperatorFlags())),
         common_(new (graph_zone()) CommonOperatorBuilder(graph_zone())),
         javascript_(new (graph_zone()) JSOperatorBuilder(graph_zone())),
         jsgraph_(new (graph_zone())
index a8b658f..0327d1c 100644 (file)
@@ -17,7 +17,7 @@ RawMachineAssembler::RawMachineAssembler(Graph* graph,
                                          MachineOperatorBuilder::Flags flags)
     : GraphBuilder(graph),
       schedule_(new (zone()) Schedule(zone())),
-      machine_(word, flags),
+      machine_(zone(), word, flags),
       common_(zone()),
       machine_sig_(machine_sig),
       call_descriptor_(
index c50b338..33a3077 100644 (file)
@@ -672,8 +672,11 @@ class RepresentationSelector {
           VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
           if (lower()) DeferReplacement(node, node->InputAt(0));
         } else if ((in & kTypeMask) == kTypeUint32 ||
-                   (in & kTypeMask) == kTypeInt32 ||
-                   in_upper->Is(Type::Unsigned32()) ||
+                   in_upper->Is(Type::Unsigned32())) {
+          // Just change representation if necessary.
+          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeInt32 | kRepWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if ((in & kTypeMask) == kTypeInt32 ||
                    (in & kRepMask) == kRepWord32) {
           // Just change representation if necessary.
           VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
@@ -697,12 +700,15 @@ class RepresentationSelector {
           VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
           if (lower()) DeferReplacement(node, node->InputAt(0));
         } else if ((in & kTypeMask) == kTypeUint32 ||
-                   (in & kTypeMask) == kTypeInt32 ||
-                   in_upper->Is(Type::Signed32()) ||
-                   (in & kRepMask) == kRepWord32) {
+                   in_upper->Is(Type::Unsigned32())) {
           // Just change representation if necessary.
           VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
           if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if ((in & kTypeMask) == kTypeInt32 ||
+                   (in & kRepMask) == kRepWord32) {
+          // Just change representation if necessary.
+          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeUint32 | kRepWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
         } else {
           // Require the input in float64 format and perform truncation.
           // TODO(turbofan): avoid a truncation with a smi check.
index 0fa2b95..99f4f89 100644 (file)
@@ -1033,8 +1033,7 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
   lhs = Rangify(lhs, t);
   rhs = Rangify(rhs, t);
   if (lhs->IsRange() && rhs->IsRange()) {
-    // TODO(titzer): fix me.
-    //    return JSModulusRanger(lhs->AsRange(), rhs->AsRange(), t);
+    return JSModulusRanger(lhs->AsRange(), rhs->AsRange(), t);
   }
   return Type::OrderedNumber();
 }
index 1bc5be7..772de4d 100644 (file)
@@ -61,6 +61,7 @@ class GraphAndBuilders {
   explicit GraphAndBuilders(Zone* zone)
       : main_graph_(new (zone) Graph(zone)),
         main_common_(zone),
+        main_machine_(zone),
         main_simplified_(zone) {}
 
  protected:
index 425a46c..3e2b857 100644 (file)
@@ -33,6 +33,7 @@ class InstructionTester : public HandleAndZoneScope {
         info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
         linkage(zone(), &info),
         common(zone()),
+        machine(zone()),
         code(NULL) {}
 
   ~InstructionTester() { delete code; }
index 2a591c1..8588f66 100644 (file)
@@ -22,7 +22,7 @@ class JSCacheTesterHelper {
         main_common_(zone),
         main_javascript_(zone),
         main_typer_(&main_graph_, MaybeHandle<Context>()),
-        main_machine_() {}
+        main_machine_(zone) {}
   Graph main_graph_;
   CommonOperatorBuilder main_common_;
   JSOperatorBuilder main_javascript_;
index 264fee0..f04e327 100644 (file)
@@ -21,7 +21,7 @@ class ContextSpecializationTester : public HandleAndZoneScope,
       : DirectGraphBuilder(new (main_zone()) Graph(main_zone())),
         common_(main_zone()),
         javascript_(main_zone()),
-        machine_(),
+        machine_(main_zone()),
         simplified_(main_zone()),
         jsgraph_(graph(), common(), &javascript_, &machine_),
         info_(main_isolate(), main_zone()) {}
index 28cc90a..7c04cf3 100644 (file)
@@ -21,6 +21,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
         binop(NULL),
         unop(NULL),
         javascript(main_zone()),
+        machine(main_zone()),
         simplified(main_zone()),
         common(main_zone()),
         graph(main_zone()),
index 115967a..ec14cd2 100644 (file)
@@ -56,6 +56,7 @@ class ReducerTester : public HandleAndZoneScope {
       : isolate(main_isolate()),
         binop(NULL),
         unop(NULL),
+        machine(main_zone()),
         common(main_zone()),
         graph(main_zone()),
         javascript(main_zone()),
index 7b4f975..d2a52c7 100644 (file)
@@ -163,7 +163,8 @@ TEST(BuildMulNodeGraph) {
   Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
+  // TODO(titzer): use test operators.
+  MachineOperatorBuilder machine(scope.main_zone());
 
   Node* start = graph.NewNode(common.Start(0));
   graph.SetStart(start);
index 659aacd..f835265 100644 (file)
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "src/v8.h"
-#include "test/cctest/cctest.h"
 
 #include "src/compiler/access-builder.h"
 #include "src/compiler/common-operator.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-operator.h"
-#include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/compiler/schedule.h"
 #include "src/compiler/scheduler.h"
 #include "src/compiler/simplified-operator.h"
 #include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
+Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, 0, 1,
+                 0, 0);
+
 // TODO(titzer): pull RPO tests out to their own file.
 static void CheckRPONumbers(BasicBlockVector* order, size_t expected,
                             bool loops_allowed) {
@@ -1571,7 +1574,6 @@ TEST(BuildScheduleSimpleLoopWithCodeMotion) {
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common_builder(scope.main_zone());
   JSOperatorBuilder js_builder(scope.main_zone());
-  MachineOperatorBuilder machine_builder;
   const Operator* op;
 
   Handle<HeapObject> object =
@@ -1607,7 +1609,7 @@ TEST(BuildScheduleSimpleLoopWithCodeMotion) {
   Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil);
   USE(n20);
   n20->ReplaceInput(0, n9);
-  op = machine_builder.Int32Add();
+  op = &kIntAdd;
   Node* n19 = graph.NewNode(op, nil, nil);
   USE(n19);
   op = common_builder.Phi(kMachAnyTagged, 2);
@@ -1731,7 +1733,6 @@ TEST(FloatingDiamond2) {
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1740,7 +1741,7 @@ TEST(FloatingDiamond2) {
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* ret = graph.NewNode(common.Return(), add, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
 
@@ -1754,7 +1755,6 @@ TEST(FloatingDiamond3) {
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1763,7 +1763,7 @@ TEST(FloatingDiamond3) {
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* d3 = CreateDiamond(&graph, &common, add);
   Node* ret = graph.NewNode(common.Return(), d3, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
@@ -1779,7 +1779,6 @@ TEST(NestedFloatingDiamonds) {
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   SimplifiedOperatorBuilder simplified(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1821,7 +1820,6 @@ TEST(NestedFloatingDiamondWithLoop) {
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   SimplifiedOperatorBuilder simplified(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1837,7 +1835,7 @@ TEST(NestedFloatingDiamondWithLoop) {
   Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
 
   // TODO(mstarzinger): Make scheduler deal with non-empty loops here.
-  // Node* add = graph.NewNode(machine.IntAdd(), ind, fv);
+  // Node* add = graph.NewNode(&kIntAdd, ind, fv);
 
   Node* br1 = graph.NewNode(common.Branch(), ind, loop);
   Node* t1 = graph.NewNode(common.IfTrue(), br1);
@@ -1863,7 +1861,6 @@ TEST(LoopedFloatingDiamond1) {
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   SimplifiedOperatorBuilder simplified(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1873,7 +1870,7 @@ TEST(LoopedFloatingDiamond1) {
   Node* c = graph.NewNode(common.Int32Constant(7));
   Node* loop = graph.NewNode(common.Loop(2), start, start);
   Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
-  Node* add = graph.NewNode(machine.IntAdd(), ind, c);
+  Node* add = graph.NewNode(&kIntAdd, ind, c);
 
   Node* br = graph.NewNode(common.Branch(), add, loop);
   Node* t = graph.NewNode(common.IfTrue(), br);
@@ -1902,7 +1899,6 @@ TEST(LoopedFloatingDiamond2) {
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   SimplifiedOperatorBuilder simplified(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1919,7 +1915,7 @@ TEST(LoopedFloatingDiamond2) {
   Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
   Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind, m1);
 
-  Node* add = graph.NewNode(machine.IntAdd(), ind, phi1);
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
 
   Node* br = graph.NewNode(common.Branch(), add, loop);
   Node* t = graph.NewNode(common.IfTrue(), br);
@@ -1942,7 +1938,6 @@ TEST(PhisPushedDownToDifferentBranches) {
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   SimplifiedOperatorBuilder simplified(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
index 5ddc10d..7fe4933 100644 (file)
@@ -744,6 +744,17 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
     }
   }
 
+  Node* ExampleWithTypeAndRep(Type* type, MachineType mach_type) {
+    FieldAccess access = {kUntaggedBase, 0, Handle<Name>::null(), type,
+                          mach_type};
+    // TODO(titzer): using loads here just to force the representation is ugly.
+    Node* node = graph()->NewNode(simplified()->LoadField(access),
+                                  jsgraph.IntPtrConstant(0), graph()->start(),
+                                  graph()->start());
+    NodeProperties::SetBounds(node, Bounds(type));
+    return node;
+  }
+
   Node* Use(Node* node, MachineType type) {
     if (type & kTypeInt32) {
       return graph()->NewNode(machine()->Int32LessThan(), node,
@@ -757,6 +768,9 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
     } else if (type & kRepWord64) {
       return graph()->NewNode(machine()->Int64LessThan(), node,
                               Int64Constant(1));
+    } else if (type & kRepWord32) {
+      return graph()->NewNode(machine()->Word32Equal(), node,
+                              jsgraph.Int32Constant(1));
     } else {
       return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
                               jsgraph.TrueConstant());
@@ -1060,9 +1074,7 @@ TEST(LowerNumberToInt32_to_ChangeTaggedToInt32) {
 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* p0 = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
   Node* use = t.Use(trunc, kMachInt32);
   t.Return(use);
@@ -1086,17 +1098,6 @@ TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32_with_change) {
 }
 
 
-TEST(LowerNumberToInt32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepTagged
-}
-
-
-TEST(LowerNumberToInt32_to_ChangeFloat64ToInt32) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepWord32
-  // | kTypeInt32
-}
-
-
 TEST(LowerNumberToUint32_to_nop) {
   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepTagged
   TestingGraph t(Type::Unsigned32());
@@ -1159,20 +1160,67 @@ TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_with_change) {
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepTagged
+TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32) {
+  // NumberToUint32(x: kRepFloat64) used as kRepWord32
+  TestingGraph t(Type::Unsigned32());
+  Node* input = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input);
+  Node* use = t.Use(trunc, kRepWord32);
+  t.Return(use);
+  t.Lower();
+  CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, input, use->InputAt(0));
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_word32) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepWord32
+  Type* types[] = {Type::Signed32(), Type::Unsigned32()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      Node* use = t.Use(trunc, static_cast<MachineType>(kRepWord32 | mach[u]));
+      t.Return(use);
+      t.Lower();
+      IrOpcode::Value opcode = i == 0 ? IrOpcode::kChangeFloat64ToInt32
+                                      : IrOpcode::kChangeFloat64ToUint32;
+      CheckChangeOf(opcode, input, use->InputAt(0));
+    }
+  }
 }
 
 
-TEST(LowerNumberToUint32_to_TruncateFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64) used as kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_tagged) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepTagged
+  Type* types[] = {Type::Signed32(), Type::Unsigned32(), Type::Any()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      // TODO(titzer): we use the store here to force the representation.
+      FieldAccess access = {kTaggedBase, 0, Handle<Name>(), types[u],
+                            static_cast<MachineType>(mach[u] | kRepTagged)};
+      Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
+                                       trunc, t.start, t.start);
+      t.Effect(store);
+      t.Lower();
+      CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, input, store->InputAt(2));
+    }
+  }
 }
 
 
diff --git a/test/mjsunit/mod-range.js b/test/mjsunit/mod-range.js
new file mode 100644 (file)
index 0000000..0cded89
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function g1(i) {
+  var x = i * 1;
+  return (x >>> 0) % 1000000000000;
+}
+
+function g2(i) {
+  var x = i * 1;
+  return ((x >>> 0) % 1000000000000) | 0;
+}
+
+function test1() {
+  assertEquals(2294967296, g1(-2000000000));
+  assertEquals(2294967295, g1(-2000000001));
+  assertEquals(2294967290, g1(-2000000006));
+
+  assertEquals(2147483651, g1(-2147483645));
+  assertEquals(2147483650, g1(-2147483646));
+  assertEquals(2147483649, g1(-2147483647));
+  assertEquals(2147483648, g1(-2147483648));
+  assertEquals(2147483647, g1(-2147483649));
+
+  assertEquals(3000000000, g1(3000000000));
+  assertEquals(3000000001, g1(3000000001));
+  assertEquals(3000000002, g1(3000000002));
+
+  assertEquals(4000000000, g1(4000000000));
+  assertEquals(4000400001, g1(4000400001));
+  assertEquals(4000400002, g1(4000400002));
+
+  assertEquals(3, g1(4294967299));
+  assertEquals(2, g1(4294967298));
+  assertEquals(1, g1(4294967297));
+  assertEquals(0, g1(4294967296));
+  assertEquals(4294967295, g1(4294967295));
+  assertEquals(4294967294, g1(4294967294));
+  assertEquals(4294967293, g1(4294967293));
+  assertEquals(4294967292, g1(4294967292));
+}
+
+%NeverOptimizeFunction(test1);
+test1();
+
+function test2() {
+  assertEquals(-2000000000, g2(-2000000000));
+  assertEquals(-2000000001, g2(-2000000001));
+  assertEquals(-2000000006, g2(-2000000006));
+
+  assertEquals(-2147483645, g2(-2147483645));
+  assertEquals(-2147483646, g2(-2147483646));
+  assertEquals(-2147483647, g2(-2147483647));
+  assertEquals(-2147483648, g2(-2147483648));
+  assertEquals(2147483647, g2(-2147483649));
+
+  assertEquals(-1294967296, g2(3000000000));
+  assertEquals(-1294967295, g2(3000000001));
+  assertEquals(-1294967294, g2(3000000002));
+
+  assertEquals(-294967296, g2(4000000000));
+  assertEquals(-294567295, g2(4000400001));
+  assertEquals(-294567294, g2(4000400002));
+
+  assertEquals(3, g2(4294967299));
+  assertEquals(2, g2(4294967298));
+  assertEquals(1, g2(4294967297));
+  assertEquals(0, g2(4294967296));
+  assertEquals(-1, g2(4294967295));
+  assertEquals(-2, g2(4294967294));
+  assertEquals(-3, g2(4294967293));
+  assertEquals(-4, g2(4294967292));
+}
+
+%NeverOptimizeFunction(test2);
+test2();
index 17d6513..7f5ec8f 100644 (file)
@@ -66,7 +66,7 @@ class ChangeLoweringTest : public GraphTest {
   }
 
   Reduction Reduce(Node* node) {
-    MachineOperatorBuilder machine(WordRepresentation());
+    MachineOperatorBuilder machine(zone(), WordRepresentation());
     JSOperatorBuilder javascript(zone());
     JSGraph jsgraph(graph(), common(), &javascript, &machine);
     CompilationInfo info(isolate(), zone());
index 0a0d8d6..48ad1b7 100644 (file)
@@ -23,7 +23,7 @@ class JSBuiltinReducerTest : public TypedGraphTest {
  protected:
   Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
                                    MachineOperatorBuilder::Flag::kNoFlags) {
-    MachineOperatorBuilder machine(kMachPtr, flags);
+    MachineOperatorBuilder machine(zone(), kMachPtr, flags);
     JSGraph jsgraph(graph(), common(), javascript(), &machine);
     JSBuiltinReducer reducer(&jsgraph);
     return reducer.Reduce(node);
index 539785d..97ffd83 100644 (file)
@@ -38,7 +38,7 @@ class JSTypedLoweringTest : public TypedGraphTest {
 
  protected:
   Reduction Reduce(Node* node) {
-    MachineOperatorBuilder machine;
+    MachineOperatorBuilder machine(zone());
     JSGraph jsgraph(graph(), common(), javascript(), &machine);
     JSTypedLowering reducer(&jsgraph);
     return reducer.Reduce(node);
index a62216d..065a734 100644 (file)
@@ -22,7 +22,7 @@ namespace compiler {
 class MachineOperatorReducerTest : public TypedGraphTest {
  public:
   explicit MachineOperatorReducerTest(int num_parameters = 2)
-      : TypedGraphTest(num_parameters) {}
+      : TypedGraphTest(num_parameters), machine_(zone()) {}
 
  protected:
   Reduction Reduce(Node* node) {
index 843a44e..f087c66 100644 (file)
@@ -18,7 +18,7 @@ namespace compiler {
 
 class NodeMatcherTest : public GraphTest {
  public:
-  NodeMatcherTest() {}
+  NodeMatcherTest() : machine_(zone()) {}
   virtual ~NodeMatcherTest() {}
 
   MachineOperatorBuilder* machine() { return &machine_; }
index 465ee84..7f8e43d 100644 (file)
@@ -22,7 +22,7 @@ class SimplifiedOperatorReducerTest : public GraphTest {
 
  protected:
   Reduction Reduce(Node* node) {
-    MachineOperatorBuilder machine;
+    MachineOperatorBuilder machine(zone());
     JSOperatorBuilder javascript(zone());
     JSGraph jsgraph(graph(), common(), &javascript, &machine);
     SimplifiedOperatorReducer reducer(&jsgraph);