Revision: 24888
Author: [email protected]
Date: Sun Oct 26 12:49:56 2014 UTC
Log: [turbofan] Implement the correct semantics for integer
division/modulus.
Also fix the sdiv/udiv instructions on ARM as a nice side effect.
TEST=cctest,unittests
[email protected]
Review URL: https://codereview.chromium.org/677483005
https://code.google.com/p/v8/source/detail?r=24888
Modified:
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/base/bits.cc
/branches/bleeding_edge/src/base/bits.h
/branches/bleeding_edge/src/compiler/machine-operator-reducer.cc
/branches/bleeding_edge/src/compiler/machine-operator-reducer.h
/branches/bleeding_edge/test/cctest/test-assembler-arm.cc
/branches/bleeding_edge/test/unittests/base/bits-unittest.cc
/branches/bleeding_edge/test/unittests/compiler/machine-operator-reducer-unittest.cc
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Oct 14 07:47:27
2014 UTC
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Sun Oct 26 12:49:56
2014 UTC
@@ -2741,15 +2741,12 @@
int rs = instr->RsValue();
int32_t rs_val = get_register(rs);
int32_t ret_val = 0;
- DCHECK(rs_val != 0);
// udiv
if (instr->Bit(21) == 0x1) {
- ret_val = static_cast<int32_t>(static_cast<uint32_t>(rm_val)
/
-
static_cast<uint32_t>(rs_val));
- } else if ((rm_val == kMinInt) && (rs_val == -1)) {
- ret_val = kMinInt;
+ ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
+ bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
} else {
- ret_val = rm_val / rs_val;
+ ret_val = base::bits::SignedDiv32(rm_val, rs_val);
}
set_register(rn, ret_val);
return;
=======================================
--- /branches/bleeding_edge/src/base/bits.cc Tue Oct 14 07:47:27 2014 UTC
+++ /branches/bleeding_edge/src/base/bits.cc Sun Oct 26 12:49:56 2014 UTC
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "src/base/bits.h"
+
+#include <limits>
+
#include "src/base/logging.h"
namespace v8 {
@@ -31,6 +34,19 @@
return bit_cast<int32_t>(bit_cast<uint32_t>(acc) +
bit_cast<uint32_t>(SignedMulHigh32(lhs, rhs)));
}
+
+
+int32_t SignedDiv32(int32_t lhs, int32_t rhs) {
+ if (rhs == 0) return 0;
+ if (rhs == -1) return -lhs;
+ return lhs / rhs;
+}
+
+
+int32_t SignedMod32(int32_t lhs, int32_t rhs) {
+ if (rhs == 0 || rhs == -1) return 0;
+ return lhs % rhs;
+}
} // namespace bits
} // namespace base
=======================================
--- /branches/bleeding_edge/src/base/bits.h Tue Oct 21 08:25:14 2014 UTC
+++ /branches/bleeding_edge/src/base/bits.h Sun Oct 26 12:49:56 2014 UTC
@@ -198,6 +198,32 @@
// |lhs| and |rhs|, extracts the most significant 32 bits of the result,
and
// adds the accumulate value |acc|.
int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc);
+
+
+// SignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient
+// truncated to int32. If |rhs| is zero, then zero is returned. If |lhs|
+// is minint and |rhs| is -1, it returns minint.
+int32_t SignedDiv32(int32_t lhs, int32_t rhs);
+
+
+// SignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder
+// truncated to int32. If either |rhs| is zero or |lhs| is minint and |rhs|
+// is -1, it returns zero.
+int32_t SignedMod32(int32_t lhs, int32_t rhs);
+
+
+// UnsignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient
+// truncated to uint32. If |rhs| is zero, then zero is returned.
+inline uint32_t UnsignedDiv32(uint32_t lhs, uint32_t rhs) {
+ return rhs ? lhs / rhs : 0u;
+}
+
+
+// UnsignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder
+// truncated to uint32. If |rhs| is zero, then zero is returned.
+inline uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs) {
+ return rhs ? lhs % rhs : 0u;
+}
} // namespace bits
} // namespace base
=======================================
--- /branches/bleeding_edge/src/compiler/machine-operator-reducer.cc Thu
Oct 23 10:22:06 2014 UTC
+++ /branches/bleeding_edge/src/compiler/machine-operator-reducer.cc Sun
Oct 26 12:49:56 2014 UTC
@@ -56,6 +56,11 @@
Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
return graph()->NewNode(machine()->Word32Shr(), lhs,
Uint32Constant(rhs));
}
+
+
+Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
+ return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
+}
Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
@@ -299,40 +304,12 @@
}
case IrOpcode::kInt32Div:
return ReduceInt32Div(node);
- case IrOpcode::kUint32Div: {
- Uint32BinopMatcher m(node);
- if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
- // TODO(turbofan): if (m.left().Is(0))
- // TODO(turbofan): if (m.right().Is(0))
- // TODO(turbofan): if (m.LeftEqualsRight())
- if (m.IsFoldable() && !m.right().Is(0)) { // K / K => K
- return ReplaceInt32(m.left().Value() / m.right().Value());
- }
- if (m.right().IsPowerOf2()) { // x / 2^n => x >> n
- node->set_op(machine()->Word32Shr());
- node->ReplaceInput(1,
Int32Constant(WhichPowerOf2(m.right().Value())));
- return Changed(node);
- }
- break;
- }
+ case IrOpcode::kUint32Div:
+ return ReduceUint32Div(node);
case IrOpcode::kInt32Mod:
return ReduceInt32Mod(node);
- case IrOpcode::kUint32Mod: {
- Uint32BinopMatcher m(node);
- if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
- // TODO(turbofan): if (m.left().Is(0))
- // TODO(turbofan): if (m.right().Is(0))
- // TODO(turbofan): if (m.LeftEqualsRight())
- if (m.IsFoldable() && !m.right().Is(0)) { // K % K => K
- return ReplaceInt32(m.left().Value() % m.right().Value());
- }
- if (m.right().IsPowerOf2()) { // x % 2^n => x & 2^n-1
- node->set_op(machine()->Word32And());
- node->ReplaceInput(1, Int32Constant(m.right().Value() - 1));
- return Changed(node);
- }
- break;
- }
+ case IrOpcode::kUint32Mod:
+ return ReduceUint32Mod(node);
case IrOpcode::kInt32LessThan: {
Int32BinopMatcher m(node);
if (m.IsFoldable()) { // K < K => K
@@ -554,13 +531,16 @@
Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
Int32BinopMatcher m(node);
+ if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0
if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
- // TODO(turbofan): if (m.left().Is(0))
- // TODO(turbofan): if (m.LeftEqualsRight())
- if (m.IsFoldable() && !m.right().Is(0)) { // K / K => K
- if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
- return ReplaceInt32(m.left().Value() / m.right().Value());
+ if (m.IsFoldable()) { // K / K => K
+ return ReplaceInt32(
+ base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
+ }
+ if (m.LeftEqualsRight()) { // x / x => x != 0
+ Node* const zero = Int32Constant(0);
+ return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
}
if (m.right().Is(-1)) { // x / -1 => 0 - x
node->set_op(machine()->Int32Sub());
@@ -593,17 +573,40 @@
}
return NoChange();
}
+
+
+Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
+ Uint32BinopMatcher m(node);
+ if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
+ if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0
+ if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
+ if (m.IsFoldable()) { // K / K => K
+ return ReplaceUint32(
+ base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
+ }
+ if (m.LeftEqualsRight()) { // x / x => x != 0
+ Node* const zero = Int32Constant(0);
+ return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
+ }
+ if (m.right().IsPowerOf2()) { // x / 2^n => x >> n
+ node->set_op(machine()->Word32Shr());
+ node->ReplaceInput(1,
Uint32Constant(WhichPowerOf2(m.right().Value())));
+ return Changed(node);
+ }
+ return NoChange();
+}
Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
Int32BinopMatcher m(node);
- if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
- if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0
- // TODO(turbofan): if (m.left().Is(0))
- // TODO(turbofan): if (m.right().Is(0))
- // TODO(turbofan): if (m.LeftEqualsRight())
- if (m.IsFoldable() && !m.right().Is(0)) { // K % K => K
- return ReplaceInt32(m.left().Value() % m.right().Value());
+ if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
+ if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
+ if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
+ if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0
+ if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
+ if (m.IsFoldable()) { // K % K => K
+ return ReplaceInt32(
+ base::bits::SignedMod32(m.left().Value(), m.right().Value()));
}
if (m.right().HasValue()) {
Node* const dividend = m.left().node();
@@ -637,6 +640,25 @@
}
return NoChange();
}
+
+
+Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
+ Uint32BinopMatcher m(node);
+ if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
+ if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
+ if (m.right().Is(1)) return ReplaceUint32(0); // x % 1 => 0
+ if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
+ if (m.IsFoldable()) { // K % K => K
+ return ReplaceUint32(
+ base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
+ }
+ if (m.right().IsPowerOf2()) { // x % 2^n => x & 2^n-1
+ node->set_op(machine()->Word32And());
+ node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
+ return Changed(node);
+ }
+ return NoChange();
+}
Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node*
node) {
=======================================
--- /branches/bleeding_edge/src/compiler/machine-operator-reducer.h Tue Oct
14 11:57:06 2014 UTC
+++ /branches/bleeding_edge/src/compiler/machine-operator-reducer.h Sun Oct
26 12:49:56 2014 UTC
@@ -37,6 +37,7 @@
Node* Word32And(Node* lhs, uint32_t rhs);
Node* Word32Sar(Node* lhs, uint32_t rhs);
Node* Word32Shr(Node* lhs, uint32_t rhs);
+ Node* Word32Equal(Node* lhs, Node* rhs);
Node* Int32Add(Node* lhs, Node* rhs);
Node* Int32Sub(Node* lhs, Node* rhs);
Node* Int32Mul(Node* lhs, Node* rhs);
@@ -53,12 +54,17 @@
Reduction ReplaceInt32(int32_t value) {
return Replace(Int32Constant(value));
}
+ Reduction ReplaceUint32(uint32_t value) {
+ return Replace(Uint32Constant(value));
+ }
Reduction ReplaceInt64(int64_t value) {
return Replace(Int64Constant(value));
}
Reduction ReduceInt32Div(Node* node);
+ Reduction ReduceUint32Div(Node* node);
Reduction ReduceInt32Mod(Node* node);
+ Reduction ReduceUint32Mod(Node* node);
Reduction ReduceProjection(size_t index, Node* node);
Graph* graph() const;
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Tue Oct 14
07:47:27 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Sun Oct 26
12:49:56 2014 UTC
@@ -1442,20 +1442,18 @@
CHECK_EQ(expected_, t.result);
-TEST(18) {
+TEST(sdiv) {
// Test the sdiv.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
+ Assembler assm(isolate, NULL, 0);
- typedef struct {
- uint32_t dividend;
- uint32_t divisor;
- uint32_t result;
- } T;
- T t;
-
- Assembler assm(isolate, NULL, 0);
+ struct T {
+ int32_t dividend;
+ int32_t divisor;
+ int32_t result;
+ } t;
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(&assm, SUDIV);
@@ -1480,6 +1478,8 @@
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
Object* dummy;
+ TEST_SDIV(0, kMinInt, 0);
+ TEST_SDIV(0, 1024, 0);
TEST_SDIV(1073741824, kMinInt, -2);
TEST_SDIV(kMinInt, kMinInt, -1);
TEST_SDIV(5, 10, 2);
@@ -1498,6 +1498,62 @@
#undef TEST_SDIV
+#define TEST_UDIV(expected_, dividend_, divisor_) \
+ t.dividend = dividend_; \
+ t.divisor = divisor_; \
+ t.result = 0; \
+ dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); \
+ CHECK_EQ(expected_, t.result);
+
+
+TEST(udiv) {
+ // Test the udiv.
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+ Assembler assm(isolate, NULL, 0);
+
+ struct T {
+ uint32_t dividend;
+ uint32_t divisor;
+ uint32_t result;
+ } t;
+
+ if (CpuFeatures::IsSupported(SUDIV)) {
+ CpuFeatureScope scope(&assm, SUDIV);
+
+ __ mov(r3, Operand(r0));
+
+ __ ldr(r0, MemOperand(r3, OFFSET_OF(T, dividend)));
+ __ ldr(r1, MemOperand(r3, OFFSET_OF(T, divisor)));
+
+ __ sdiv(r2, r0, r1);
+ __ str(r2, MemOperand(r3, OFFSET_OF(T, result)));
+
+ __ bx(lr);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+ OFStream os(stdout);
+ code->Print(os);
+#endif
+ F3 f = FUNCTION_CAST<F3>(code->entry());
+ Object* dummy;
+ TEST_UDIV(0, 0, 0);
+ TEST_UDIV(0, 1024, 0);
+ TEST_UDIV(5, 10, 2);
+ TEST_UDIV(3, 10, 3);
+ USE(dummy);
+ }
+}
+
+
+#undef TEST_UDIV
+
+
TEST(smmla) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
=======================================
--- /branches/bleeding_edge/test/unittests/base/bits-unittest.cc Tue Oct 14
07:47:27 2014 UTC
+++ /branches/bleeding_edge/test/unittests/base/bits-unittest.cc Sun Oct 26
12:49:56 2014 UTC
@@ -223,6 +223,58 @@
EXPECT_EQ(i + 1, SignedMulHighAndAdd32(1024 * 1024 * 1024, 4, i));
}
}
+
+
+TEST(Bits, SignedDiv32) {
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(),
+ SignedDiv32(std::numeric_limits<int32_t>::min(), -1));
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(),
+ SignedDiv32(std::numeric_limits<int32_t>::max(), 1));
+ TRACED_FORRANGE(int32_t, i, 0, 50) {
+ EXPECT_EQ(0, SignedDiv32(i, 0));
+ TRACED_FORRANGE(int32_t, j, 1, i) {
+ EXPECT_EQ(1, SignedDiv32(j, j));
+ EXPECT_EQ(i / j, SignedDiv32(i, j));
+ EXPECT_EQ(-i / j, SignedDiv32(i, -j));
+ }
+ }
+}
+
+
+TEST(Bits, SignedMod32) {
+ EXPECT_EQ(0, SignedMod32(std::numeric_limits<int32_t>::min(), -1));
+ EXPECT_EQ(0, SignedMod32(std::numeric_limits<int32_t>::max(), 1));
+ TRACED_FORRANGE(int32_t, i, 0, 50) {
+ EXPECT_EQ(0, SignedMod32(i, 0));
+ TRACED_FORRANGE(int32_t, j, 1, i) {
+ EXPECT_EQ(0, SignedMod32(j, j));
+ EXPECT_EQ(i % j, SignedMod32(i, j));
+ EXPECT_EQ(i % j, SignedMod32(i, -j));
+ }
+ }
+}
+
+
+TEST(Bits, UnsignedDiv32) {
+ TRACED_FORRANGE(uint32_t, i, 0, 50) {
+ EXPECT_EQ(0u, UnsignedDiv32(i, 0));
+ TRACED_FORRANGE(uint32_t, j, i + 1, 100) {
+ EXPECT_EQ(1u, UnsignedDiv32(j, j));
+ EXPECT_EQ(i / j, UnsignedDiv32(i, j));
+ }
+ }
+}
+
+
+TEST(Bits, UnsignedMod32) {
+ TRACED_FORRANGE(uint32_t, i, 0, 50) {
+ EXPECT_EQ(0u, UnsignedMod32(i, 0));
+ TRACED_FORRANGE(uint32_t, j, i + 1, 100) {
+ EXPECT_EQ(0u, UnsignedMod32(j, j));
+ EXPECT_EQ(i % j, UnsignedMod32(i, j));
+ }
+ }
+}
} // namespace bits
} // namespace base
=======================================
---
/branches/bleeding_edge/test/unittests/compiler/machine-operator-reducer-unittest.cc
Tue Oct 21 12:24:01 2014 UTC
+++
/branches/bleeding_edge/test/unittests/compiler/machine-operator-reducer-unittest.cc
Sun Oct 26 12:49:56 2014 UTC
@@ -729,6 +729,71 @@
}
}
}
+
+
+TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
+ Node* const p0 = Parameter(0);
+ Reduction const r = Reduce(graph()->NewNode(machine()->Int32Div(), p0,
p0));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsWord32Equal(IsWord32Equal(p0, IsInt32Constant(0)),
IsInt32Constant(0)));
+}
+
+
+//
-----------------------------------------------------------------------------
+// Uint32Div
+
+
+TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
+ Node* const p0 = Parameter(0);
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Uint32Div(), Int32Constant(0),
p0));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
Int32Constant(0)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
Int32Constant(1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_EQ(r.replacement(), p0);
+ }
+ TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
+ TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
+ Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(),
+ Uint32Constant(dividend),
+
Uint32Constant(divisor)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsInt32Constant(bit_cast<int32_t>(
+ base::bits::UnsignedDiv32(dividend, divisor))));
+ }
+ }
+ TRACED_FORRANGE(uint32_t, shift, 1, 31) {
+ Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
+ Uint32Constant(1u <<
shift)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shr(p0,
IsInt32Constant(bit_cast<int32_t>(shift))));
+ }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
+ Node* const p0 = Parameter(0);
+ Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
p0));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsWord32Equal(IsWord32Equal(p0, IsInt32Constant(0)),
IsInt32Constant(0)));
+}
//
-----------------------------------------------------------------------------
@@ -737,13 +802,40 @@
TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
Node* const p0 = Parameter(0);
- static const int32_t kOnes[] = {-1, 1};
- TRACED_FOREACH(int32_t, one, kOnes) {
+ {
Reduction const r =
- Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
Int32Constant(one)));
+ Reduce(graph()->NewNode(machine()->Int32Mod(), Int32Constant(0),
p0));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
}
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
Int32Constant(0)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
Int32Constant(1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
Int32Constant(-1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ TRACED_FOREACH(int32_t, dividend, kInt32Values) {
+ TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+ Reduction const r = Reduce(graph()->NewNode(machine()->Int32Mod(),
+ Int32Constant(dividend),
+ Int32Constant(divisor)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsInt32Constant(base::bits::SignedMod32(dividend,
divisor)));
+ }
+ }
TRACED_FORRANGE(int32_t, shift, 1, 30) {
Reduction const r = Reduce(
graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1 <<
shift)));
@@ -795,6 +887,68 @@
IsInt32Constant(Abs(divisor)))));
}
}
+
+
+TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
+ Node* const p0 = Parameter(0);
+ Reduction const r = Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
p0));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+}
+
+
+//
-----------------------------------------------------------------------------
+// Uint32Mod
+
+
+TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
+ Node* const p0 = Parameter(0);
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
Int32Constant(0)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Uint32Mod(), Int32Constant(0),
p0));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ {
+ Reduction const r =
+ Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
Int32Constant(1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+ }
+ TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
+ TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
+ Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(),
+ Uint32Constant(dividend),
+
Uint32Constant(divisor)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsInt32Constant(bit_cast<int32_t>(
+ base::bits::UnsignedMod32(dividend, divisor))));
+ }
+ }
+ TRACED_FORRANGE(uint32_t, shift, 1, 31) {
+ Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
+ Uint32Constant(1u <<
shift)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32And(p0, IsInt32Constant(
+ bit_cast<int32_t>((1u << shift) -
1u))));
+ }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
+ Node* const p0 = Parameter(0);
+ Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
p0));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+}
//
-----------------------------------------------------------------------------
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.