Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc
index 96fb965..147aa32 100644
--- a/test/cctest/compiler/test-simplified-lowering.cc
+++ b/test/cctest/compiler/test-simplified-lowering.cc
@@ -5,8 +5,9 @@
#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,11 +36,10 @@
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()),
- lowering(&jsgraph) {}
+ jsgraph(this->graph(), this->common(), &javascript, this->machine()),
+ lowering(&jsgraph, this->zone()) {}
Typer typer;
JSOperatorBuilder javascript;
@@ -48,16 +48,40 @@
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(), this->zone());
+ 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 +92,7 @@
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 +121,7 @@
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 +139,6 @@
}
}
}
-#endif
// Create a simple JSObject with a unique map.
@@ -207,10 +232,8 @@
TEST(RunLoadStoreFixedArrayIndex) {
SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
ElementAccess access = AccessBuilder::ForFixedArrayElement();
- Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
- t.Int32Constant(2));
- t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
- load);
+ Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
+ t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
t.Return(load);
t.LowerAllNodes();
@@ -235,14 +258,13 @@
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 =
- t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
- t.Int32Constant(array_length));
+ t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
- t.Int32Constant(array_length), load);
+ load);
t.Return(t.jsgraph.TrueConstant());
t.LowerAllNodes();
@@ -329,9 +351,8 @@
kMachAnyTagged};
SimplifiedLoweringTester<Object*> t;
- Node* load = t.LoadElement(
- access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
- t.Int32Constant(static_cast<int>(arraysize(smis))));
+ Node* load = t.LoadElement(access, t.PointerConstant(smis),
+ t.Int32Constant(static_cast<int>(j)));
t.Return(load);
t.LowerAllNodes();
@@ -360,8 +381,7 @@
SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
Node* p0 = t.Parameter(0);
t.StoreElement(access, t.PointerConstant(smis),
- t.Int32Constant(static_cast<int>(j)),
- t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
+ t.Int32Constant(static_cast<int>(j)), p0);
t.Return(p0);
t.LowerAllNodes();
@@ -427,10 +447,8 @@
SimplifiedLoweringTester<Object*> t;
Node* ptr = GetBaseNode(&t);
- Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
- t.Int32Constant(static_cast<int>(num_elements)));
- t.StoreElement(access, ptr, t.Int32Constant(to_index),
- t.Int32Constant(static_cast<int>(num_elements)), load);
+ Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
+ t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
t.Return(t.jsgraph.TrueConstant());
t.LowerAllNodes();
t.GenerateCode();
@@ -648,9 +666,9 @@
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 +678,7 @@
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));
@@ -679,10 +698,7 @@
CHECK_EQ(expected, node->opcode());
}
- void Lower() {
- SimplifiedLowering lowering(&jsgraph);
- lowering.LowerAllNodes();
- }
+ void Lower() { SimplifiedLowering(&jsgraph, jsgraph.zone()).LowerAllNodes(); }
// Inserts the node as the return value of the graph.
Node* Return(Node* node) {
@@ -718,6 +734,17 @@
}
}
+ 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,
@@ -731,6 +758,9 @@
} 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());
@@ -757,6 +787,50 @@
};
+TEST(LowerAnyToBoolean_bit_bit) {
+ // AnyToBoolean(x: kRepBit) used as kRepBit
+ HandleAndZoneScope scope;
+ Factory* f = scope.main_zone()->isolate()->factory();
+ Handle<Object> zero = f->NewNumber(0);
+ Handle<Object> one = f->NewNumber(1);
+ Type* singleton_zero = Type::Constant(zero, scope.main_zone());
+ Type* singleton_one = Type::Constant(one, scope.main_zone());
+ Type* zero_one_range = Type::Range(zero, one, scope.main_zone());
+ static Type* kTypes[] = {
+ singleton_zero, singleton_one, zero_one_range, Type::Boolean(),
+ Type::Union(Type::Boolean(), singleton_zero, scope.main_zone()),
+ Type::Union(Type::Boolean(), singleton_one, scope.main_zone()),
+ Type::Union(Type::Boolean(), zero_one_range, scope.main_zone())};
+ for (Type* type : kTypes) {
+ TestingGraph t(type);
+ Node* x = t.ExampleWithTypeAndRep(type, kRepBit);
+ Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+ Node* use = t.Branch(cnv);
+ t.Lower();
+ CHECK_EQ(x, use->InputAt(0));
+ }
+}
+
+
+#if V8_TURBOFAN_TARGET
+
+TEST(LowerAnyToBoolean_tagged_tagged) {
+ // AnyToBoolean(x: kRepTagged) used as kRepTagged
+ TestingGraph t(Type::Any());
+ Node* x = t.p0;
+ Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+ Node* use = t.Use(cnv, kRepTagged);
+ t.Return(use);
+ t.Lower();
+ CHECK_EQ(IrOpcode::kCall, cnv->opcode());
+ CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode());
+ CHECK_EQ(x, cnv->InputAt(1));
+ CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2));
+}
+
+#endif
+
+
TEST(LowerBooleanNot_bit_bit) {
// BooleanNot(x: kRepBit) used as kRepBit
TestingGraph t(Type::Boolean());
@@ -765,7 +839,7 @@
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 +856,7 @@
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 +995,50 @@
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 +1058,10 @@
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());
+ }
}
}
@@ -1006,7 +1108,7 @@
TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
// NumberToInt32(x: kRepFloat64) used as kMachInt32
TestingGraph t(Type::Number());
- Node* p0 = t.ExampleWithOutput(kMachFloat64);
+ 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);
@@ -1030,17 +1132,6 @@
}
-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());
@@ -1078,6 +1169,8 @@
// 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);
@@ -1101,20 +1194,67 @@
}
-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));
+ }
+ }
}
@@ -1268,45 +1408,54 @@
}
+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 +1463,7 @@
CheckFieldAccessArithmetic(access, load);
MachineType rep = OpParameter<MachineType>(load);
- CHECK_EQ(machine_reps[i], rep);
+ CHECK_EQ(kMachineReps[i], rep);
}
}
@@ -1322,12 +1471,12 @@
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 +1486,10 @@
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 +1497,13 @@
TEST(LowerLoadElement_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++) {
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
- Type::Any(), machine_reps[i]};
+ 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]);
+ Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
+ t.p1, t.start, t.start);
+ Node* use = t.Use(load, kMachineReps[i]);
t.Return(use);
t.Lower();
CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1363,7 +1511,7 @@
CheckElementAccessArithmetic(access, load);
MachineType rep = OpParameter<MachineType>(load);
- CHECK_EQ(machine_reps[i], rep);
+ CHECK_EQ(kMachineReps[i], rep);
}
}
@@ -1371,14 +1519,13 @@
TEST(LowerStoreElement_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++) {
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
- Type::Any(), machine_reps[i]};
+ 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);
+ t.p1, val, t.start, t.start);
t.Effect(store);
t.Lower();
CHECK_EQ(IrOpcode::kStore, store->opcode());
@@ -1386,10 +1533,10 @@
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());
}
}
@@ -1397,12 +1544,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());
+ TestingGraph t(Type::Any(), Type::Signed32());
ElementAccess access = {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.start, t.start);
t.Return(load);
t.Lower();
CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1416,12 +1563,12 @@
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());
+ TestingGraph t(Type::Any(), Type::Signed32());
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
kMachAnyTagged};
Node* store =
- t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
+ t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
t.jsgraph.TrueConstant(), t.start, t.start);
t.Effect(store);
t.Lower();
@@ -1440,7 +1587,7 @@
kMachFloat64};
Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
- t.p1, t.p1, t.start);
+ t.p1, t.start, t.start);
t.Return(load);
t.Lower();
CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1467,13 +1614,13 @@
TEST(InsertChangeForStoreElement) {
// TODO(titzer): test all load/store representation change insertions.
- TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+ TestingGraph t(Type::Any(), Type::Signed32());
ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
kMachFloat64};
- Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
- t.jsgraph.Int32Constant(0), t.p2, t.p1,
- t.start, t.start);
+ Node* store =
+ t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
+ t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
t.Effect(store);
t.Lower();
@@ -1504,10 +1651,11 @@
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 +1673,405 @@
}
-// 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();
+
+ struct TestData {
+ Type* arg1;
+ Type* arg2;
+ MachineType use;
+ MachineTypeUnion expected;
+ };
+
+ TestData test_data[] = {
+ {Type::Signed32(), Type::Unsigned32(), kMachInt32,
+ kRepWord32 | kTypeNumber},
+ {Type::Signed32(), Type::Unsigned32(), 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));
+ }
}