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) {
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags;
return MachineOperatorBuilder::kInt32DivIsSafe |
MachineOperatorBuilder::kInt32ModIsSafe |
MachineOperatorBuilder::kUint32DivIsSafe |
MachineOperatorBuilder::kUint32ModIsSafe;
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -1300,8 +1300,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags;
return MachineOperatorBuilder::kNoFlags;
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -881,8 +881,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags;
return MachineOperatorBuilder::kNoFlags;
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -555,6 +555,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
node->set_op(machine()->Int32Sub());
node->ReplaceInput(0, Int32Constant(0));
node->ReplaceInput(1, m.left().node());
node->TrimInputCount(2);
return Changed(node);
}
if (m.right().HasValue()) {
......@@ -576,6 +577,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
node->set_op(machine()->Int32Sub());
node->ReplaceInput(0, Int32Constant(0));
node->ReplaceInput(1, quotient);
node->TrimInputCount(2);
return Changed(node);
}
return Replace(quotient);
......@@ -644,6 +646,7 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
node->set_op(machine()->Int32Sub());
DCHECK_EQ(dividend, node->InputAt(0));
node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
node->TrimInputCount(2);
return Changed(node);
}
}
......
......@@ -60,17 +60,21 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
public:
// Flags that specify which operations are available. This is useful
// for operations that are unsupported by some back-ends.
enum class Flag : unsigned {
kNoFlags = 0,
kFloat64Floor = 1 << 0,
kFloat64Ceil = 1 << 1,
kFloat64RoundTruncate = 1 << 2,
kFloat64RoundTiesAway = 1 << 3
enum Flag {
kNoFlags = 0u,
kFloat64Floor = 1u << 0,
kFloat64Ceil = 1u << 1,
kFloat64RoundTruncate = 1u << 2,
kFloat64RoundTiesAway = 1u << 3,
kInt32DivIsSafe = 1u << 4,
kInt32ModIsSafe = 1u << 5,
kUint32DivIsSafe = 1u << 6,
kUint32ModIsSafe = 1u << 7
};
typedef base::Flags<Flag, unsigned> Flags;
explicit MachineOperatorBuilder(MachineType word = kMachPtr,
Flags supportedOperators = Flag::kNoFlags);
Flags supportedOperators = kNoFlags);
const Operator* Word32And();
const Operator* Word32Or();
......@@ -104,6 +108,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Uint32LessThan();
const Operator* Uint32LessThanOrEqual();
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* Int64Sub();
......@@ -153,14 +161,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Float64Ceil();
const Operator* Float64RoundTruncate();
const Operator* Float64RoundTiesAway();
bool HasFloat64Floor() { return flags_ & Flag::kFloat64Floor; }
bool HasFloat64Ceil() { return flags_ & Flag::kFloat64Ceil; }
bool HasFloat64RoundTruncate() {
return flags_ & Flag::kFloat64RoundTruncate;
}
bool HasFloat64RoundTiesAway() {
return flags_ & Flag::kFloat64RoundTiesAway;
}
bool HasFloat64Floor() { return flags_ & kFloat64Floor; }
bool HasFloat64Ceil() { return flags_ & kFloat64Ceil; }
bool HasFloat64RoundTruncate() { return flags_ & kFloat64RoundTruncate; }
bool HasFloat64RoundTiesAway() { return flags_ & kFloat64RoundTiesAway; }
// load [base + index]
const Operator* Load(LoadRepresentation rep);
......
......@@ -139,6 +139,7 @@ typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
// Fairly intel-specify node matcher used for matching scale factors in
......
......@@ -123,6 +123,10 @@ inline int OperatorProperties::GetControlInputCount(const Operator* op) {
case IrOpcode::kEffectPhi:
case IrOpcode::kLoad:
case IrOpcode::kLoadField:
case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod:
case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod:
return 1;
#define OPCODE_CASE(x) case IrOpcode::k##x:
CONTROL_OP_LIST(OPCODE_CASE)
......
......@@ -605,19 +605,17 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberDivide: {
NumberMatcher right(node->InputAt(1));
if (right.HasValue() && !right.Is(0) && !right.Is(-1)) {
if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Div
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
break;
} else if (CanLowerToUint32Binop(node, use)) {
// => unsigned Uint32Div
VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node));
break;
}
if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Div
VisitInt32Binop(node);
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
break;
}
if (CanLowerToUint32Binop(node, use)) {
// => unsigned Uint32Div
VisitUint32Binop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
break;
}
// => Float64Div
VisitFloat64Binop(node);
......@@ -625,20 +623,17 @@ class RepresentationSelector {
break;
}
case IrOpcode::kNumberModulus: {
NumberMatcher right(node->InputAt(1));
if (right.HasValue() && !right.Is(0) && !right.Is(-1)) {
if (BothInputsAre(node, Type::Signed32()) &&
!CanObserveMinusZero(use)) {
// => signed Int32Mod
VisitInt32Binop(node);
if (lower()) node->set_op(Int32Op(node));
break;
} else if (BothInputsAre(node, Type::Unsigned32())) {
// => unsigned Uint32Mod
VisitUint32Binop(node);
if (lower()) node->set_op(Uint32Op(node));
break;
}
if (CanLowerToInt32Binop(node, use)) {
// => signed Int32Mod
VisitInt32Binop(node);
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
break;
}
if (CanLowerToUint32Binop(node, use)) {
// => unsigned Uint32Mod
VisitUint32Binop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
break;
}
// => Float64Mod
VisitFloat64Binop(node);
......@@ -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) {
node->set_op(machine()->WordEqual());
node->ReplaceInput(0, StringComparison(node, false));
......
......@@ -42,6 +42,10 @@ class SimplifiedLowering FINAL {
Node* OffsetMinusTagConstant(int32_t offset);
Node* ComputeIndex(const ElementAccess& access, Node* index);
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;
......
......@@ -1112,8 +1112,9 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::Flag::kNoFlags;
return MachineOperatorBuilder::kNoFlags;
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -1720,11 +1720,11 @@ TEST(NumberDivide_TruncatingToInt32) {
TestingGraph t(Type::Signed32());
Node* k = t.jsgraph.Constant(constants[i]);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), div);
t.Return(trunc);
Node* use = t.Use(div, kMachInt32);
t.Return(use);
t.Lower();
CHECK_EQ(IrOpcode::kInt32Div, div->opcode());
CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
}
}
......@@ -1761,11 +1761,11 @@ TEST(NumberDivide_TruncatingToUint32) {
TestingGraph t(Type::Unsigned32());
Node* k = t.jsgraph.Constant(constants[i]);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), div);
t.Return(trunc);
Node* use = t.Use(div, kMachUint32);
t.Return(use);
t.Lower();
CHECK_EQ(IrOpcode::kUint32Div, div->opcode());
CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
}
}
......@@ -1795,28 +1795,39 @@ TEST(RunNumberDivide_TruncatingToUint32) {
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());
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* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), div);
t.Return(trunc);
Node* use = t.Use(div, kMachInt32);
t.Return(use);
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());
Node* k = t.jsgraph.Constant(0);
Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), div);
t.Return(trunc);
Node* use = t.Use(div, kMachUint32);
t.Return(use);
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) {
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);
Node* use = t.Use(mod, kMachInt32);
t.Return(use);
t.Lower();
CHECK_EQ(IrOpcode::kInt32Mod, mod->opcode());
CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
}
}
......@@ -1870,10 +1881,10 @@ TEST(NumberModulus_TruncatingToUint32) {
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);
t.Return(trunc);
Node* ret = t.Return(trunc);
t.Lower();
CHECK_EQ(IrOpcode::kUint32Mod, mod->opcode());
CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
}
}
......@@ -1916,45 +1927,3 @@ TEST(NumberModulus_Int32) {
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 {
const Operator* (MachineOperatorBuilder::*constructor)();
IrOpcode::Value opcode;
int value_input_count;
int control_input_count;
int value_output_count;
};
......@@ -168,43 +169,41 @@ std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
const PureOperator kPureOperators[] = {
#define PURE(Name, input_count, output_count) \
{ \
&MachineOperatorBuilder::Name, IrOpcode::k##Name, input_count, \
output_count \
#define PURE(Name, value_input_count, control_input_count, value_output_count) \
{ \
&MachineOperatorBuilder::Name, IrOpcode::k##Name, value_input_count, \
control_input_count, value_output_count \
}
PURE(Word32And, 2, 1), PURE(Word32Or, 2, 1),
PURE(Word32Xor, 2, 1), PURE(Word32Shl, 2, 1),
PURE(Word32Shr, 2, 1), PURE(Word32Sar, 2, 1),
PURE(Word32Ror, 2, 1), PURE(Word32Equal, 2, 1),
PURE(Word64And, 2, 1), PURE(Word64Or, 2, 1),
PURE(Word64Xor, 2, 1), PURE(Word64Shl, 2, 1),
PURE(Word64Shr, 2, 1), PURE(Word64Sar, 2, 1),
PURE(Word64Ror, 2, 1), PURE(Word64Equal, 2, 1),
PURE(Int32Add, 2, 1), PURE(Int32AddWithOverflow, 2, 2),
PURE(Int32Sub, 2, 1), PURE(Int32SubWithOverflow, 2, 2),
PURE(Int32Mul, 2, 1), PURE(Int32MulHigh, 2, 1),
PURE(Int32Div, 2, 1), PURE(Uint32Div, 2, 1),
PURE(Int32Mod, 2, 1), PURE(Uint32Mod, 2, 1),
PURE(Int32LessThan, 2, 1), PURE(Int32LessThanOrEqual, 2, 1),
PURE(Uint32LessThan, 2, 1), PURE(Uint32LessThanOrEqual, 2, 1),
PURE(Int64Add, 2, 1), PURE(Int64Sub, 2, 1),
PURE(Int64Mul, 2, 1), PURE(Int64Div, 2, 1),
PURE(Uint64Div, 2, 1), PURE(Int64Mod, 2, 1),
PURE(Uint64Mod, 2, 1), PURE(Int64LessThan, 2, 1),
PURE(Int64LessThanOrEqual, 2, 1), PURE(Uint64LessThan, 2, 1),
PURE(ChangeFloat32ToFloat64, 1, 1), PURE(ChangeFloat64ToInt32, 1, 1),
PURE(ChangeFloat64ToUint32, 1, 1), PURE(ChangeInt32ToInt64, 1, 1),
PURE(ChangeUint32ToFloat64, 1, 1), PURE(ChangeUint32ToUint64, 1, 1),
PURE(TruncateFloat64ToFloat32, 1, 1), PURE(TruncateFloat64ToInt32, 1, 1),
PURE(TruncateInt64ToInt32, 1, 1), PURE(Float64Add, 2, 1),
PURE(Float64Sub, 2, 1), PURE(Float64Mul, 2, 1),
PURE(Float64Div, 2, 1), PURE(Float64Mod, 2, 1),
PURE(Float64Sqrt, 1, 1), PURE(Float64Equal, 2, 1),
PURE(Float64LessThan, 2, 1), PURE(Float64LessThanOrEqual, 2, 1),
PURE(LoadStackPointer, 0, 1), PURE(Float64Floor, 1, 1),
PURE(Float64Ceil, 1, 1), PURE(Float64RoundTruncate, 1, 1),
PURE(Float64RoundTiesAway, 1, 1),
PURE(Word32And, 2, 0, 1), PURE(Word32Or, 2, 0, 1), PURE(Word32Xor, 2, 0, 1),
PURE(Word32Shl, 2, 0, 1), PURE(Word32Shr, 2, 0, 1),
PURE(Word32Sar, 2, 0, 1), PURE(Word32Ror, 2, 0, 1),
PURE(Word32Equal, 2, 0, 1), PURE(Word64And, 2, 0, 1),
PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), PURE(Word64Shl, 2, 0, 1),
PURE(Word64Shr, 2, 0, 1), PURE(Word64Sar, 2, 0, 1),
PURE(Word64Ror, 2, 0, 1), PURE(Word64Equal, 2, 0, 1),
PURE(Int32Add, 2, 0, 1), PURE(Int32AddWithOverflow, 2, 0, 2),
PURE(Int32Sub, 2, 0, 1), PURE(Int32SubWithOverflow, 2, 0, 2),
PURE(Int32Mul, 2, 0, 1), PURE(Int32MulHigh, 2, 0, 1),
PURE(Int32Div, 2, 1, 1), PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1),
PURE(Uint32Mod, 2, 1, 1), PURE(Int32LessThan, 2, 0, 1),
PURE(Int32LessThanOrEqual, 2, 0, 1), PURE(Uint32LessThan, 2, 0, 1),
PURE(Uint32LessThanOrEqual, 2, 0, 1), PURE(Int64Add, 2, 0, 1),
PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), PURE(Int64Div, 2, 0, 1),
PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), PURE(Uint64Mod, 2, 0, 1),
PURE(Int64LessThan, 2, 0, 1), PURE(Int64LessThanOrEqual, 2, 0, 1),
PURE(Uint64LessThan, 2, 0, 1), PURE(ChangeFloat32ToFloat64, 1, 0, 1),
PURE(ChangeFloat64ToInt32, 1, 0, 1), PURE(ChangeFloat64ToUint32, 1, 0, 1),
PURE(ChangeInt32ToInt64, 1, 0, 1), PURE(ChangeUint32ToFloat64, 1, 0, 1),
PURE(ChangeUint32ToUint64, 1, 0, 1),
PURE(TruncateFloat64ToFloat32, 1, 0, 1),
PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1),
PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1),
PURE(Float64Mul, 2, 0, 1), PURE(Float64Div, 2, 0, 1),
PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1),
PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1)
#undef PURE
};
......@@ -229,8 +228,10 @@ TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) {
EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(pop.control_input_count,
OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(pop.value_input_count + pop.control_input_count,
OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(pop.value_output_count,
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