Commit 81aaeb47 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Complete support for integer division/modulus in simplified lowering.

Also add backend flags that tell whether integer division/modulus is
generally safe, i.e. does not trap on overflow or divide by zero.

TEST=unittests
R=dcarney@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#24942}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24942 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d3eb7e8e
...@@ -1139,8 +1139,12 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { ...@@ -1139,8 +1139,12 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static // static
MachineOperatorBuilder::Flags MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() { InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags; return MachineOperatorBuilder::kInt32DivIsSafe |
MachineOperatorBuilder::kInt32ModIsSafe |
MachineOperatorBuilder::kUint32DivIsSafe |
MachineOperatorBuilder::kUint32ModIsSafe;
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -1300,8 +1300,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { ...@@ -1300,8 +1300,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static // static
MachineOperatorBuilder::Flags MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() { InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags; return MachineOperatorBuilder::kNoFlags;
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -881,8 +881,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { ...@@ -881,8 +881,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static // static
MachineOperatorBuilder::Flags MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() { InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags; return MachineOperatorBuilder::kNoFlags;
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -555,6 +555,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { ...@@ -555,6 +555,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
node->set_op(machine()->Int32Sub()); node->set_op(machine()->Int32Sub());
node->ReplaceInput(0, Int32Constant(0)); node->ReplaceInput(0, Int32Constant(0));
node->ReplaceInput(1, m.left().node()); node->ReplaceInput(1, m.left().node());
node->TrimInputCount(2);
return Changed(node); return Changed(node);
} }
if (m.right().HasValue()) { if (m.right().HasValue()) {
...@@ -576,6 +577,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { ...@@ -576,6 +577,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
node->set_op(machine()->Int32Sub()); node->set_op(machine()->Int32Sub());
node->ReplaceInput(0, Int32Constant(0)); node->ReplaceInput(0, Int32Constant(0));
node->ReplaceInput(1, quotient); node->ReplaceInput(1, quotient);
node->TrimInputCount(2);
return Changed(node); return Changed(node);
} }
return Replace(quotient); return Replace(quotient);
...@@ -644,6 +646,7 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) { ...@@ -644,6 +646,7 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
node->set_op(machine()->Int32Sub()); node->set_op(machine()->Int32Sub());
DCHECK_EQ(dividend, node->InputAt(0)); DCHECK_EQ(dividend, node->InputAt(0));
node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor))); node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
node->TrimInputCount(2);
return Changed(node); return Changed(node);
} }
} }
......
...@@ -60,17 +60,21 @@ class MachineOperatorBuilder FINAL : public ZoneObject { ...@@ -60,17 +60,21 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
public: public:
// Flags that specify which operations are available. This is useful // Flags that specify which operations are available. This is useful
// for operations that are unsupported by some back-ends. // for operations that are unsupported by some back-ends.
enum class Flag : unsigned { enum Flag {
kNoFlags = 0, kNoFlags = 0u,
kFloat64Floor = 1 << 0, kFloat64Floor = 1u << 0,
kFloat64Ceil = 1 << 1, kFloat64Ceil = 1u << 1,
kFloat64RoundTruncate = 1 << 2, kFloat64RoundTruncate = 1u << 2,
kFloat64RoundTiesAway = 1 << 3 kFloat64RoundTiesAway = 1u << 3,
kInt32DivIsSafe = 1u << 4,
kInt32ModIsSafe = 1u << 5,
kUint32DivIsSafe = 1u << 6,
kUint32ModIsSafe = 1u << 7
}; };
typedef base::Flags<Flag, unsigned> Flags; typedef base::Flags<Flag, unsigned> Flags;
explicit MachineOperatorBuilder(MachineType word = kMachPtr, explicit MachineOperatorBuilder(MachineType word = kMachPtr,
Flags supportedOperators = Flag::kNoFlags); Flags supportedOperators = kNoFlags);
const Operator* Word32And(); const Operator* Word32And();
const Operator* Word32Or(); const Operator* Word32Or();
...@@ -104,6 +108,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject { ...@@ -104,6 +108,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Uint32LessThan(); const Operator* Uint32LessThan();
const Operator* Uint32LessThanOrEqual(); const Operator* Uint32LessThanOrEqual();
const Operator* Uint32Mod(); const Operator* Uint32Mod();
bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; }
bool Int32ModIsSafe() const { return flags_ & kInt32ModIsSafe; }
bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; }
bool Uint32ModIsSafe() const { return flags_ & kUint32ModIsSafe; }
const Operator* Int64Add(); const Operator* Int64Add();
const Operator* Int64Sub(); const Operator* Int64Sub();
...@@ -153,14 +161,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject { ...@@ -153,14 +161,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Float64Ceil(); const Operator* Float64Ceil();
const Operator* Float64RoundTruncate(); const Operator* Float64RoundTruncate();
const Operator* Float64RoundTiesAway(); const Operator* Float64RoundTiesAway();
bool HasFloat64Floor() { return flags_ & Flag::kFloat64Floor; } bool HasFloat64Floor() { return flags_ & kFloat64Floor; }
bool HasFloat64Ceil() { return flags_ & Flag::kFloat64Ceil; } bool HasFloat64Ceil() { return flags_ & kFloat64Ceil; }
bool HasFloat64RoundTruncate() { bool HasFloat64RoundTruncate() { return flags_ & kFloat64RoundTruncate; }
return flags_ & Flag::kFloat64RoundTruncate; bool HasFloat64RoundTiesAway() { return flags_ & kFloat64RoundTiesAway; }
}
bool HasFloat64RoundTiesAway() {
return flags_ & Flag::kFloat64RoundTiesAway;
}
// load [base + index] // load [base + index]
const Operator* Load(LoadRepresentation rep); const Operator* Load(LoadRepresentation rep);
......
...@@ -139,6 +139,7 @@ typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher; ...@@ -139,6 +139,7 @@ typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher; typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher; typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher; typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
// Fairly intel-specify node matcher used for matching scale factors in // Fairly intel-specify node matcher used for matching scale factors in
......
...@@ -123,6 +123,10 @@ inline int OperatorProperties::GetControlInputCount(const Operator* op) { ...@@ -123,6 +123,10 @@ inline int OperatorProperties::GetControlInputCount(const Operator* op) {
case IrOpcode::kEffectPhi: case IrOpcode::kEffectPhi:
case IrOpcode::kLoad: case IrOpcode::kLoad:
case IrOpcode::kLoadField: case IrOpcode::kLoadField:
case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod:
case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod:
return 1; return 1;
#define OPCODE_CASE(x) case IrOpcode::k##x: #define OPCODE_CASE(x) case IrOpcode::k##x:
CONTROL_OP_LIST(OPCODE_CASE) CONTROL_OP_LIST(OPCODE_CASE)
......
...@@ -605,41 +605,36 @@ class RepresentationSelector { ...@@ -605,41 +605,36 @@ class RepresentationSelector {
break; break;
} }
case IrOpcode::kNumberDivide: { case IrOpcode::kNumberDivide: {
NumberMatcher right(node->InputAt(1));
if (right.HasValue() && !right.Is(0) && !right.Is(-1)) {
if (CanLowerToInt32Binop(node, use)) { if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Div // => signed Int32Div
VisitInt32Binop(node); VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node)); if (lower()) DeferReplacement(node, lowering->Int32Div(node));
break; break;
} else if (CanLowerToUint32Binop(node, use)) { }
if (CanLowerToUint32Binop(node, use)) {
// => unsigned Uint32Div // => unsigned Uint32Div
VisitUint32Binop(node); VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node)); if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
break; break;
} }
}
// => Float64Div // => Float64Div
VisitFloat64Binop(node); VisitFloat64Binop(node);
if (lower()) node->set_op(Float64Op(node)); if (lower()) node->set_op(Float64Op(node));
break; break;
} }
case IrOpcode::kNumberModulus: { case IrOpcode::kNumberModulus: {
NumberMatcher right(node->InputAt(1)); if (CanLowerToInt32Binop(node, use)) {
if (right.HasValue() && !right.Is(0) && !right.Is(-1)) {
if (BothInputsAre(node, Type::Signed32()) &&
!CanObserveMinusZero(use)) {
// => signed Int32Mod // => signed Int32Mod
VisitInt32Binop(node); VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node)); if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
break; break;
} else if (BothInputsAre(node, Type::Unsigned32())) { }
if (CanLowerToUint32Binop(node, use)) {
// => unsigned Uint32Mod // => unsigned Uint32Mod
VisitUint32Binop(node); VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node)); if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
break; break;
} }
}
// => Float64Mod // => Float64Mod
VisitFloat64Binop(node); VisitFloat64Binop(node);
if (lower()) node->set_op(Float64Op(node)); if (lower()) node->set_op(Float64Op(node));
...@@ -1218,6 +1213,148 @@ Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) { ...@@ -1218,6 +1213,148 @@ Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
} }
Node* SimplifiedLowering::Int32Div(Node* const node) {
Int32BinopMatcher m(node);
Node* const zero = jsgraph()->Int32Constant(0);
Node* const lhs = m.left().node();
Node* const rhs = m.right().node();
if (m.right().Is(-1)) {
return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
} else if (m.right().Is(0)) {
return rhs;
} else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
}
Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
graph()->start());
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* true0 = zero;
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* false0 = nullptr;
{
Node* check1 = graph()->NewNode(machine()->Word32Equal(), rhs,
jsgraph()->Int32Constant(-1));
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* true1 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* false1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_false1);
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
false0 = graph()->NewNode(common()->Phi(kMachInt32, 2), true1, false1,
if_false0);
}
Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
return graph()->NewNode(common()->Phi(kMachInt32, 2), true0, false0, merge0);
}
Node* SimplifiedLowering::Int32Mod(Node* const node) {
Int32BinopMatcher m(node);
Node* const zero = jsgraph()->Int32Constant(0);
Node* const lhs = m.left().node();
Node* const rhs = m.right().node();
if (m.right().Is(-1) || m.right().Is(0)) {
return zero;
} else if (machine()->Int32ModIsSafe() || m.right().HasValue()) {
return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
}
Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
graph()->start());
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* true0 = zero;
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* false0 = nullptr;
{
Node* check1 = graph()->NewNode(machine()->Word32Equal(), rhs,
jsgraph()->Int32Constant(-1));
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* true1 = zero;
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* false1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_false1);
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
false0 = graph()->NewNode(common()->Phi(kMachInt32, 2), true1, false1,
if_false0);
}
Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
return graph()->NewNode(common()->Phi(kMachInt32, 2), true0, false0, merge0);
}
Node* SimplifiedLowering::Uint32Div(Node* const node) {
Uint32BinopMatcher m(node);
Node* const zero = jsgraph()->Uint32Constant(0);
Node* const lhs = m.left().node();
Node* const rhs = m.right().node();
if (m.right().Is(0)) {
return zero;
} else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
}
Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), check,
graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* vtrue = zero;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, if_false);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
return graph()->NewNode(common()->Phi(kMachUint32, 2), vtrue, vfalse, merge);
}
Node* SimplifiedLowering::Uint32Mod(Node* const node) {
Uint32BinopMatcher m(node);
Node* const zero = jsgraph()->Uint32Constant(0);
Node* const lhs = m.left().node();
Node* const rhs = m.right().node();
if (m.right().Is(0)) {
return zero;
} else if (machine()->Uint32ModIsSafe() || m.right().HasValue()) {
return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
}
Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), check,
graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* vtrue = zero;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_false);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
return graph()->NewNode(common()->Phi(kMachUint32, 2), vtrue, vfalse, merge);
}
void SimplifiedLowering::DoStringEqual(Node* node) { void SimplifiedLowering::DoStringEqual(Node* node) {
node->set_op(machine()->WordEqual()); node->set_op(machine()->WordEqual());
node->ReplaceInput(0, StringComparison(node, false)); node->ReplaceInput(0, StringComparison(node, false));
......
...@@ -42,6 +42,10 @@ class SimplifiedLowering FINAL { ...@@ -42,6 +42,10 @@ class SimplifiedLowering FINAL {
Node* OffsetMinusTagConstant(int32_t offset); Node* OffsetMinusTagConstant(int32_t offset);
Node* ComputeIndex(const ElementAccess& access, Node* index); Node* ComputeIndex(const ElementAccess& access, Node* index);
Node* StringComparison(Node* node, bool requires_ordering); Node* StringComparison(Node* node, bool requires_ordering);
Node* Int32Div(Node* const node);
Node* Int32Mod(Node* const node);
Node* Uint32Div(Node* const node);
Node* Uint32Mod(Node* const node);
friend class RepresentationSelector; friend class RepresentationSelector;
......
...@@ -1112,8 +1112,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { ...@@ -1112,8 +1112,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static // static
MachineOperatorBuilder::Flags MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() { InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags; return MachineOperatorBuilder::kNoFlags;
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -1720,11 +1720,11 @@ TEST(NumberDivide_TruncatingToInt32) { ...@@ -1720,11 +1720,11 @@ TEST(NumberDivide_TruncatingToInt32) {
TestingGraph t(Type::Signed32()); TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(constants[i]); Node* k = t.jsgraph.Constant(constants[i]);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), div); Node* use = t.Use(div, kMachInt32);
t.Return(trunc); t.Return(use);
t.Lower(); t.Lower();
CHECK_EQ(IrOpcode::kInt32Div, div->opcode()); CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
} }
} }
...@@ -1761,11 +1761,11 @@ TEST(NumberDivide_TruncatingToUint32) { ...@@ -1761,11 +1761,11 @@ TEST(NumberDivide_TruncatingToUint32) {
TestingGraph t(Type::Unsigned32()); TestingGraph t(Type::Unsigned32());
Node* k = t.jsgraph.Constant(constants[i]); Node* k = t.jsgraph.Constant(constants[i]);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), div); Node* use = t.Use(div, kMachUint32);
t.Return(trunc); t.Return(use);
t.Lower(); t.Lower();
CHECK_EQ(IrOpcode::kUint32Div, div->opcode()); CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
} }
} }
...@@ -1795,28 +1795,39 @@ TEST(RunNumberDivide_TruncatingToUint32) { ...@@ -1795,28 +1795,39 @@ TEST(RunNumberDivide_TruncatingToUint32) {
TEST(NumberDivide_BadConstants) { TEST(NumberDivide_BadConstants) {
int32_t constants[] = {-1, 0}; {
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();
for (size_t i = 0; i < arraysize(constants); i++) { CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
}
{
TestingGraph t(Type::Signed32()); TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(constants[i]); Node* k = t.jsgraph.Constant(0);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), div); Node* use = t.Use(div, kMachInt32);
t.Return(trunc); t.Return(use);
t.Lower(); t.Lower();
CHECK_EQ(IrOpcode::kFloat64Div, div->opcode()); CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
} }
{ {
TestingGraph t(Type::Unsigned32()); TestingGraph t(Type::Unsigned32());
Node* k = t.jsgraph.Constant(0); Node* k = t.jsgraph.Constant(0);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), div); Node* use = t.Use(div, kMachUint32);
t.Return(trunc); t.Return(use);
t.Lower(); t.Lower();
CHECK_EQ(IrOpcode::kFloat64Div, div->opcode()); CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
} }
} }
...@@ -1828,11 +1839,11 @@ TEST(NumberModulus_TruncatingToInt32) { ...@@ -1828,11 +1839,11 @@ TEST(NumberModulus_TruncatingToInt32) {
TestingGraph t(Type::Signed32()); TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(constants[i]); Node* k = t.jsgraph.Constant(constants[i]);
Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mod); Node* use = t.Use(mod, kMachInt32);
t.Return(trunc); t.Return(use);
t.Lower(); t.Lower();
CHECK_EQ(IrOpcode::kInt32Mod, mod->opcode()); CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
} }
} }
...@@ -1870,10 +1881,10 @@ TEST(NumberModulus_TruncatingToUint32) { ...@@ -1870,10 +1881,10 @@ TEST(NumberModulus_TruncatingToUint32) {
Node* k = t.jsgraph.Constant(constants[i]); Node* k = t.jsgraph.Constant(constants[i]);
Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod); Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
t.Return(trunc); Node* ret = t.Return(trunc);
t.Lower(); t.Lower();
CHECK_EQ(IrOpcode::kUint32Mod, mod->opcode()); CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
} }
} }
...@@ -1916,45 +1927,3 @@ TEST(NumberModulus_Int32) { ...@@ -1916,45 +1927,3 @@ TEST(NumberModulus_Int32) {
CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); // Pesky -0 behavior. CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); // Pesky -0 behavior.
} }
} }
TEST(NumberModulus_Uint32) {
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);
t.Return(mod);
t.Lower();
CHECK_EQ(IrOpcode::kUint32Mod, mod->opcode());
}
}
TEST(NumberModulus_BadConstants) {
int32_t constants[] = {-1, 0};
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* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mod);
t.Return(trunc);
t.Lower();
CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode());
}
{
TestingGraph t(Type::Unsigned32());
Node* k = t.jsgraph.Constant(0);
Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
t.Return(trunc);
t.Lower();
CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode());
}
}
...@@ -158,6 +158,7 @@ struct PureOperator { ...@@ -158,6 +158,7 @@ struct PureOperator {
const Operator* (MachineOperatorBuilder::*constructor)(); const Operator* (MachineOperatorBuilder::*constructor)();
IrOpcode::Value opcode; IrOpcode::Value opcode;
int value_input_count; int value_input_count;
int control_input_count;
int value_output_count; int value_output_count;
}; };
...@@ -168,43 +169,41 @@ std::ostream& operator<<(std::ostream& os, const PureOperator& pop) { ...@@ -168,43 +169,41 @@ std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
const PureOperator kPureOperators[] = { const PureOperator kPureOperators[] = {
#define PURE(Name, input_count, output_count) \ #define PURE(Name, value_input_count, control_input_count, value_output_count) \
{ \ { \
&MachineOperatorBuilder::Name, IrOpcode::k##Name, input_count, \ &MachineOperatorBuilder::Name, IrOpcode::k##Name, value_input_count, \
output_count \ control_input_count, value_output_count \
} }
PURE(Word32And, 2, 1), PURE(Word32Or, 2, 1), PURE(Word32And, 2, 0, 1), PURE(Word32Or, 2, 0, 1), PURE(Word32Xor, 2, 0, 1),
PURE(Word32Xor, 2, 1), PURE(Word32Shl, 2, 1), PURE(Word32Shl, 2, 0, 1), PURE(Word32Shr, 2, 0, 1),
PURE(Word32Shr, 2, 1), PURE(Word32Sar, 2, 1), PURE(Word32Sar, 2, 0, 1), PURE(Word32Ror, 2, 0, 1),
PURE(Word32Ror, 2, 1), PURE(Word32Equal, 2, 1), PURE(Word32Equal, 2, 0, 1), PURE(Word64And, 2, 0, 1),
PURE(Word64And, 2, 1), PURE(Word64Or, 2, 1), PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), PURE(Word64Shl, 2, 0, 1),
PURE(Word64Xor, 2, 1), PURE(Word64Shl, 2, 1), PURE(Word64Shr, 2, 0, 1), PURE(Word64Sar, 2, 0, 1),
PURE(Word64Shr, 2, 1), PURE(Word64Sar, 2, 1), PURE(Word64Ror, 2, 0, 1), PURE(Word64Equal, 2, 0, 1),
PURE(Word64Ror, 2, 1), PURE(Word64Equal, 2, 1), PURE(Int32Add, 2, 0, 1), PURE(Int32AddWithOverflow, 2, 0, 2),
PURE(Int32Add, 2, 1), PURE(Int32AddWithOverflow, 2, 2), PURE(Int32Sub, 2, 0, 1), PURE(Int32SubWithOverflow, 2, 0, 2),
PURE(Int32Sub, 2, 1), PURE(Int32SubWithOverflow, 2, 2), PURE(Int32Mul, 2, 0, 1), PURE(Int32MulHigh, 2, 0, 1),
PURE(Int32Mul, 2, 1), PURE(Int32MulHigh, 2, 1), PURE(Int32Div, 2, 1, 1), PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1),
PURE(Int32Div, 2, 1), PURE(Uint32Div, 2, 1), PURE(Uint32Mod, 2, 1, 1), PURE(Int32LessThan, 2, 0, 1),
PURE(Int32Mod, 2, 1), PURE(Uint32Mod, 2, 1), PURE(Int32LessThanOrEqual, 2, 0, 1), PURE(Uint32LessThan, 2, 0, 1),
PURE(Int32LessThan, 2, 1), PURE(Int32LessThanOrEqual, 2, 1), PURE(Uint32LessThanOrEqual, 2, 0, 1), PURE(Int64Add, 2, 0, 1),
PURE(Uint32LessThan, 2, 1), PURE(Uint32LessThanOrEqual, 2, 1), PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), PURE(Int64Div, 2, 0, 1),
PURE(Int64Add, 2, 1), PURE(Int64Sub, 2, 1), PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), PURE(Uint64Mod, 2, 0, 1),
PURE(Int64Mul, 2, 1), PURE(Int64Div, 2, 1), PURE(Int64LessThan, 2, 0, 1), PURE(Int64LessThanOrEqual, 2, 0, 1),
PURE(Uint64Div, 2, 1), PURE(Int64Mod, 2, 1), PURE(Uint64LessThan, 2, 0, 1), PURE(ChangeFloat32ToFloat64, 1, 0, 1),
PURE(Uint64Mod, 2, 1), PURE(Int64LessThan, 2, 1), PURE(ChangeFloat64ToInt32, 1, 0, 1), PURE(ChangeFloat64ToUint32, 1, 0, 1),
PURE(Int64LessThanOrEqual, 2, 1), PURE(Uint64LessThan, 2, 1), PURE(ChangeInt32ToInt64, 1, 0, 1), PURE(ChangeUint32ToFloat64, 1, 0, 1),
PURE(ChangeFloat32ToFloat64, 1, 1), PURE(ChangeFloat64ToInt32, 1, 1), PURE(ChangeUint32ToUint64, 1, 0, 1),
PURE(ChangeFloat64ToUint32, 1, 1), PURE(ChangeInt32ToInt64, 1, 1), PURE(TruncateFloat64ToFloat32, 1, 0, 1),
PURE(ChangeUint32ToFloat64, 1, 1), PURE(ChangeUint32ToUint64, 1, 1), PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1),
PURE(TruncateFloat64ToFloat32, 1, 1), PURE(TruncateFloat64ToInt32, 1, 1), PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1),
PURE(TruncateInt64ToInt32, 1, 1), PURE(Float64Add, 2, 1), PURE(Float64Mul, 2, 0, 1), PURE(Float64Div, 2, 0, 1),
PURE(Float64Sub, 2, 1), PURE(Float64Mul, 2, 1), PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
PURE(Float64Div, 2, 1), PURE(Float64Mod, 2, 1), PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
PURE(Float64Sqrt, 1, 1), PURE(Float64Equal, 2, 1), PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
PURE(Float64LessThan, 2, 1), PURE(Float64LessThanOrEqual, 2, 1), PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1),
PURE(LoadStackPointer, 0, 1), PURE(Float64Floor, 1, 1), PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1)
PURE(Float64Ceil, 1, 1), PURE(Float64RoundTruncate, 1, 1),
PURE(Float64RoundTiesAway, 1, 1),
#undef PURE #undef PURE
}; };
...@@ -229,8 +228,10 @@ TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) { ...@@ -229,8 +228,10 @@ TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) {
EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op)); EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op)); EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op)); EXPECT_EQ(pop.control_input_count,
EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op)); OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(pop.value_input_count + pop.control_input_count,
OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(pop.value_output_count, EXPECT_EQ(pop.value_output_count,
OperatorProperties::GetValueOutputCount(op)); OperatorProperties::GetValueOutputCount(op));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment