Commit f5357637 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[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
R=jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#24888}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24888 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a13acdf6
...@@ -2741,15 +2741,12 @@ void Simulator::DecodeType3(Instruction* instr) { ...@@ -2741,15 +2741,12 @@ void Simulator::DecodeType3(Instruction* instr) {
int rs = instr->RsValue(); int rs = instr->RsValue();
int32_t rs_val = get_register(rs); int32_t rs_val = get_register(rs);
int32_t ret_val = 0; int32_t ret_val = 0;
DCHECK(rs_val != 0);
// udiv // udiv
if (instr->Bit(21) == 0x1) { if (instr->Bit(21) == 0x1) {
ret_val = static_cast<int32_t>(static_cast<uint32_t>(rm_val) / ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
static_cast<uint32_t>(rs_val)); bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
} else if ((rm_val == kMinInt) && (rs_val == -1)) {
ret_val = kMinInt;
} else { } else {
ret_val = rm_val / rs_val; ret_val = base::bits::SignedDiv32(rm_val, rs_val);
} }
set_register(rn, ret_val); set_register(rn, ret_val);
return; return;
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/base/bits.h" #include "src/base/bits.h"
#include <limits>
#include "src/base/logging.h" #include "src/base/logging.h"
namespace v8 { namespace v8 {
...@@ -32,6 +35,19 @@ int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc) { ...@@ -32,6 +35,19 @@ int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc) {
bit_cast<uint32_t>(SignedMulHigh32(lhs, rhs))); 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 bits
} // namespace base } // namespace base
} // namespace v8 } // namespace v8
...@@ -199,6 +199,32 @@ int32_t SignedMulHigh32(int32_t lhs, int32_t rhs); ...@@ -199,6 +199,32 @@ int32_t SignedMulHigh32(int32_t lhs, int32_t rhs);
// adds the accumulate value |acc|. // adds the accumulate value |acc|.
int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t 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 bits
} // namespace base } // namespace base
} // namespace v8 } // namespace v8
......
...@@ -58,6 +58,11 @@ Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) { ...@@ -58,6 +58,11 @@ Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
} }
Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
}
Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) { Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
return graph()->NewNode(machine()->Int32Add(), lhs, rhs); return graph()->NewNode(machine()->Int32Add(), lhs, rhs);
} }
...@@ -299,40 +304,12 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -299,40 +304,12 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
} }
case IrOpcode::kInt32Div: case IrOpcode::kInt32Div:
return ReduceInt32Div(node); return ReduceInt32Div(node);
case IrOpcode::kUint32Div: { case IrOpcode::kUint32Div:
Uint32BinopMatcher m(node); return ReduceUint32Div(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::kInt32Mod: case IrOpcode::kInt32Mod:
return ReduceInt32Mod(node); return ReduceInt32Mod(node);
case IrOpcode::kUint32Mod: { case IrOpcode::kUint32Mod:
Uint32BinopMatcher m(node); return ReduceUint32Mod(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::kInt32LessThan: { case IrOpcode::kInt32LessThan: {
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.IsFoldable()) { // K < K => K if (m.IsFoldable()) { // K < K => K
...@@ -554,13 +531,16 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -554,13 +531,16 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
Int32BinopMatcher m(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(0)) return Replace(m.right().node()); // x / 0 => 0
if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
// TODO(turbofan): if (m.left().Is(0)) if (m.IsFoldable()) { // K / K => K
// TODO(turbofan): if (m.LeftEqualsRight()) return ReplaceInt32(
if (m.IsFoldable() && !m.right().Is(0)) { // K / K => K base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value()); }
return ReplaceInt32(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 if (m.right().Is(-1)) { // x / -1 => 0 - x
node->set_op(machine()->Int32Sub()); node->set_op(machine()->Int32Sub());
...@@ -595,15 +575,38 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { ...@@ -595,15 +575,38 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
} }
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) { Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0 if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0 if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
// TODO(turbofan): if (m.left().Is(0)) if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
// TODO(turbofan): if (m.right().Is(0)) if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0
// TODO(turbofan): if (m.LeftEqualsRight()) if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
if (m.IsFoldable() && !m.right().Is(0)) { // K % K => K if (m.IsFoldable()) { // K % K => K
return ReplaceInt32(m.left().Value() % m.right().Value()); return ReplaceInt32(
base::bits::SignedMod32(m.left().Value(), m.right().Value()));
} }
if (m.right().HasValue()) { if (m.right().HasValue()) {
Node* const dividend = m.left().node(); Node* const dividend = m.left().node();
...@@ -639,6 +642,25 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) { ...@@ -639,6 +642,25 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
} }
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) { Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow: { case IrOpcode::kInt32AddWithOverflow: {
......
...@@ -37,6 +37,7 @@ class MachineOperatorReducer FINAL : public Reducer { ...@@ -37,6 +37,7 @@ class MachineOperatorReducer FINAL : public Reducer {
Node* Word32And(Node* lhs, uint32_t rhs); Node* Word32And(Node* lhs, uint32_t rhs);
Node* Word32Sar(Node* lhs, uint32_t rhs); Node* Word32Sar(Node* lhs, uint32_t rhs);
Node* Word32Shr(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* Int32Add(Node* lhs, Node* rhs);
Node* Int32Sub(Node* lhs, Node* rhs); Node* Int32Sub(Node* lhs, Node* rhs);
Node* Int32Mul(Node* lhs, Node* rhs); Node* Int32Mul(Node* lhs, Node* rhs);
...@@ -53,12 +54,17 @@ class MachineOperatorReducer FINAL : public Reducer { ...@@ -53,12 +54,17 @@ class MachineOperatorReducer FINAL : public Reducer {
Reduction ReplaceInt32(int32_t value) { Reduction ReplaceInt32(int32_t value) {
return Replace(Int32Constant(value)); return Replace(Int32Constant(value));
} }
Reduction ReplaceUint32(uint32_t value) {
return Replace(Uint32Constant(value));
}
Reduction ReplaceInt64(int64_t value) { Reduction ReplaceInt64(int64_t value) {
return Replace(Int64Constant(value)); return Replace(Int64Constant(value));
} }
Reduction ReduceInt32Div(Node* node); Reduction ReduceInt32Div(Node* node);
Reduction ReduceUint32Div(Node* node);
Reduction ReduceInt32Mod(Node* node); Reduction ReduceInt32Mod(Node* node);
Reduction ReduceUint32Mod(Node* node);
Reduction ReduceProjection(size_t index, Node* node); Reduction ReduceProjection(size_t index, Node* node);
Graph* graph() const; Graph* graph() const;
......
...@@ -1442,21 +1442,19 @@ TEST(17) { ...@@ -1442,21 +1442,19 @@ TEST(17) {
CHECK_EQ(expected_, t.result); CHECK_EQ(expected_, t.result);
TEST(18) { TEST(sdiv) {
// Test the sdiv. // Test the sdiv.
CcTest::InitializeVM(); CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate); HandleScope scope(isolate);
typedef struct {
uint32_t dividend;
uint32_t divisor;
uint32_t result;
} T;
T t;
Assembler assm(isolate, NULL, 0); Assembler assm(isolate, NULL, 0);
struct T {
int32_t dividend;
int32_t divisor;
int32_t result;
} t;
if (CpuFeatures::IsSupported(SUDIV)) { if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(&assm, SUDIV); CpuFeatureScope scope(&assm, SUDIV);
...@@ -1480,6 +1478,8 @@ TEST(18) { ...@@ -1480,6 +1478,8 @@ TEST(18) {
#endif #endif
F3 f = FUNCTION_CAST<F3>(code->entry()); F3 f = FUNCTION_CAST<F3>(code->entry());
Object* dummy; Object* dummy;
TEST_SDIV(0, kMinInt, 0);
TEST_SDIV(0, 1024, 0);
TEST_SDIV(1073741824, kMinInt, -2); TEST_SDIV(1073741824, kMinInt, -2);
TEST_SDIV(kMinInt, kMinInt, -1); TEST_SDIV(kMinInt, kMinInt, -1);
TEST_SDIV(5, 10, 2); TEST_SDIV(5, 10, 2);
...@@ -1498,6 +1498,62 @@ TEST(18) { ...@@ -1498,6 +1498,62 @@ TEST(18) {
#undef TEST_SDIV #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) { TEST(smmla) {
CcTest::InitializeVM(); CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate(); Isolate* const isolate = CcTest::i_isolate();
......
...@@ -224,6 +224,58 @@ TEST(Bits, SignedMulHighAndAdd32) { ...@@ -224,6 +224,58 @@ TEST(Bits, SignedMulHighAndAdd32) {
} }
} }
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 bits
} // namespace base } // namespace base
} // namespace v8 } // namespace v8
...@@ -731,19 +731,111 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) { ...@@ -731,19 +731,111 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
} }
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)));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Int32Mod // Int32Mod
TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) { TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
Node* const p0 = Parameter(0); 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(), 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 = Reduction const r =
Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(one))); Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1)));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsInt32Constant(0)); 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) { TRACED_FORRANGE(int32_t, shift, 1, 30) {
Reduction const r = Reduce( Reduction const r = Reduce(
graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1 << shift))); graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1 << shift)));
...@@ -797,6 +889,68 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) { ...@@ -797,6 +889,68 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
} }
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));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Int32AddWithOverflow // Int32AddWithOverflow
......
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