Commit 481772ac authored by Rodolph Perfetta's avatar Rodolph Perfetta

[turbofan] remove redundant '& 0x1F' for shifts.

JavaScript shifts perform an implicit '& 0x1F' on their right operand, this
patch removes it when the underlying architecture already does it.

BUG=
R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25438}
parent 6d41045b
...@@ -1414,7 +1414,8 @@ InstructionSelector::SupportedMachineOperatorFlags() { ...@@ -1414,7 +1414,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::kFloat64Floor | return MachineOperatorBuilder::kFloat64Floor |
MachineOperatorBuilder::kFloat64Ceil | MachineOperatorBuilder::kFloat64Ceil |
MachineOperatorBuilder::kFloat64RoundTruncate | MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesAway; MachineOperatorBuilder::kFloat64RoundTiesAway |
MachineOperatorBuilder::kWord32ShiftIsSafe;
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -524,13 +524,6 @@ static inline void VisitShift(InstructionSelector* selector, Node* node, ...@@ -524,13 +524,6 @@ static inline void VisitShift(InstructionSelector* selector, Node* node,
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
g.UseImmediate(right)); g.UseImmediate(right));
} else { } else {
Int32BinopMatcher m(node);
if (m.right().IsWord32And()) {
Int32BinopMatcher mright(right);
if (mright.right().Is(0x1F)) {
right = mright.left().node();
}
}
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
g.UseFixed(right, ecx)); g.UseFixed(right, ecx));
} }
...@@ -1096,7 +1089,8 @@ InstructionSelector::SupportedMachineOperatorFlags() { ...@@ -1096,7 +1089,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
if (CpuFeatures::IsSupported(SSE4_1)) { if (CpuFeatures::IsSupported(SSE4_1)) {
return MachineOperatorBuilder::kFloat64Floor | return MachineOperatorBuilder::kFloat64Floor |
MachineOperatorBuilder::kFloat64Ceil | MachineOperatorBuilder::kFloat64Ceil |
MachineOperatorBuilder::kFloat64RoundTruncate; MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kWord32ShiftIsSafe;
} }
return MachineOperatorBuilder::Flag::kNoFlags; return MachineOperatorBuilder::Flag::kNoFlags;
} }
......
...@@ -151,29 +151,31 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -151,29 +151,31 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
Int32BinopMatcher mleft(m.left().node()); Int32BinopMatcher mleft(m.left().node());
Int32BinopMatcher mright(m.right().node()); Int32BinopMatcher mright(m.right().node());
if (mleft.left().node() == mright.left().node()) { if (mleft.left().node() == mright.left().node()) {
// (x << y) | (x >> (32 - y)) => x ror y // TODO(turbofan): here we are matching rotate left, shall we add
// support for rotate right?
// (x << y) | (x >>> (32 - y)) => x ror (32 - y)
if (mright.right().IsInt32Sub()) { if (mright.right().IsInt32Sub()) {
Int32BinopMatcher mrightright(mright.right().node()); Int32BinopMatcher mrightright(mright.right().node());
if (mrightright.left().Is(32) && if (mrightright.left().Is(32) &&
mrightright.right().node() == mleft.right().node()) { mrightright.right().node() == mleft.right().node()) {
node->set_op(machine()->Word32Ror()); node->set_op(machine()->Word32Ror());
node->ReplaceInput(0, mleft.left().node()); node->ReplaceInput(0, mleft.left().node());
node->ReplaceInput(1, mleft.right().node()); node->ReplaceInput(1, mright.right().node());
return Changed(node); return Changed(node);
} }
} }
// (x << K) | (x >> (32 - K)) => x ror K // (x << K) | (x >>> (32 - K)) => x ror (32 - K)
if (mleft.right().IsInRange(0, 31) && if (mleft.right().IsInRange(0, 31) &&
mright.right().Is(32 - mleft.right().Value())) { mright.right().Is(32 - mleft.right().Value())) {
node->set_op(machine()->Word32Ror()); node->set_op(machine()->Word32Ror());
node->ReplaceInput(0, mleft.left().node()); node->ReplaceInput(0, mleft.left().node());
node->ReplaceInput(1, mleft.right().node()); node->ReplaceInput(1, mright.right().node());
return Changed(node); return Changed(node);
} }
} }
} }
if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) { if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
// (x >> (32 - y)) | (x << y) => x ror y // (x >>> (32 - y)) | (x << y) => x ror (32 -y)
Int32BinopMatcher mleft(m.left().node()); Int32BinopMatcher mleft(m.left().node());
Int32BinopMatcher mright(m.right().node()); Int32BinopMatcher mright(m.right().node());
if (mleft.left().node() == mright.left().node()) { if (mleft.left().node() == mright.left().node()) {
...@@ -183,16 +185,16 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -183,16 +185,16 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
mleftright.right().node() == mright.right().node()) { mleftright.right().node() == mright.right().node()) {
node->set_op(machine()->Word32Ror()); node->set_op(machine()->Word32Ror());
node->ReplaceInput(0, mright.left().node()); node->ReplaceInput(0, mright.left().node());
node->ReplaceInput(1, mright.right().node()); node->ReplaceInput(1, mleft.right().node());
return Changed(node); return Changed(node);
} }
} }
// (x >> (32 - K)) | (x << K) => x ror K // (x >>> (32 - K)) | (x << K) => x ror (32 - K)
if (mright.right().IsInRange(0, 31) && if (mright.right().IsInRange(0, 31) &&
mleft.right().Is(32 - mright.right().Value())) { mleft.right().Is(32 - mright.right().Value())) {
node->set_op(machine()->Word32Ror()); node->set_op(machine()->Word32Ror());
node->ReplaceInput(0, mright.left().node()); node->ReplaceInput(0, mright.left().node());
node->ReplaceInput(1, mright.right().node()); node->ReplaceInput(1, mleft.right().node());
return Changed(node); return Changed(node);
} }
} }
...@@ -234,7 +236,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -234,7 +236,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
} }
} }
} }
break; return ReduceWord32Shifts(node);
} }
case IrOpcode::kWord32Shr: { case IrOpcode::kWord32Shr: {
Uint32BinopMatcher m(node); Uint32BinopMatcher m(node);
...@@ -242,7 +244,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -242,7 +244,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
if (m.IsFoldable()) { // K >>> K => K if (m.IsFoldable()) { // K >>> K => K
return ReplaceInt32(m.left().Value() >> m.right().Value()); return ReplaceInt32(m.left().Value() >> m.right().Value());
} }
break; return ReduceWord32Shifts(node);
} }
case IrOpcode::kWord32Sar: { case IrOpcode::kWord32Sar: {
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
...@@ -265,7 +267,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -265,7 +267,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
} }
} }
} }
break; return ReduceWord32Shifts(node);
} }
case IrOpcode::kWord32Ror: { case IrOpcode::kWord32Ror: {
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
...@@ -805,6 +807,27 @@ Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) { ...@@ -805,6 +807,27 @@ Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
} }
Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
(node->opcode() == IrOpcode::kWord32Shr) ||
(node->opcode() == IrOpcode::kWord32Sar));
if (machine()->Word32ShiftIsSafe()) {
// Remove the explicit 'and' with 0x1f if the shift provided by the machine
// instruction matches that required by JavaScript.
Int32BinopMatcher m(node);
if (m.right().IsWord32And()) {
Int32BinopMatcher mright(m.right().node());
if (mright.right().Is(0x1f)) {
node->ReplaceInput(1, mright.left().node());
return Changed(node);
}
}
}
return NoChange();
}
CommonOperatorBuilder* MachineOperatorReducer::common() const { CommonOperatorBuilder* MachineOperatorReducer::common() const {
return jsgraph()->common(); return jsgraph()->common();
} }
......
...@@ -68,6 +68,7 @@ class MachineOperatorReducer FINAL : public Reducer { ...@@ -68,6 +68,7 @@ class MachineOperatorReducer FINAL : public Reducer {
Reduction ReduceTruncateFloat64ToInt32(Node* node); Reduction ReduceTruncateFloat64ToInt32(Node* node);
Reduction ReduceStore(Node* node); Reduction ReduceStore(Node* node);
Reduction ReduceProjection(size_t index, Node* node); Reduction ReduceProjection(size_t index, Node* node);
Reduction ReduceWord32Shifts(Node* node);
Graph* graph() const; Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
......
...@@ -67,7 +67,8 @@ class MachineOperatorBuilder FINAL : public ZoneObject { ...@@ -67,7 +67,8 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
kFloat64RoundTruncate = 1u << 2, kFloat64RoundTruncate = 1u << 2,
kFloat64RoundTiesAway = 1u << 3, kFloat64RoundTiesAway = 1u << 3,
kInt32DivIsSafe = 1u << 4, kInt32DivIsSafe = 1u << 4,
kUint32DivIsSafe = 1u << 5 kUint32DivIsSafe = 1u << 5,
kWord32ShiftIsSafe = 1u << 6
}; };
typedef base::Flags<Flag, unsigned> Flags; typedef base::Flags<Flag, unsigned> Flags;
...@@ -82,6 +83,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject { ...@@ -82,6 +83,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Word32Sar(); const Operator* Word32Sar();
const Operator* Word32Ror(); const Operator* Word32Ror();
const Operator* Word32Equal(); const Operator* Word32Equal();
bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
const Operator* Word64And(); const Operator* Word64And();
const Operator* Word64Or(); const Operator* Word64Or();
......
...@@ -275,12 +275,6 @@ void VisitWord32Shift(InstructionSelector* selector, Node* node, ...@@ -275,12 +275,6 @@ void VisitWord32Shift(InstructionSelector* selector, Node* node,
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
g.UseImmediate(right)); g.UseImmediate(right));
} else { } else {
if (m.right().IsWord32And()) {
Int32BinopMatcher mright(right);
if (mright.right().Is(0x1F)) {
right = mright.left().node();
}
}
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
g.UseFixed(right, rcx)); g.UseFixed(right, rcx));
} }
...@@ -1170,7 +1164,8 @@ InstructionSelector::SupportedMachineOperatorFlags() { ...@@ -1170,7 +1164,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
if (CpuFeatures::IsSupported(SSE4_1)) { if (CpuFeatures::IsSupported(SSE4_1)) {
return MachineOperatorBuilder::kFloat64Floor | return MachineOperatorBuilder::kFloat64Floor |
MachineOperatorBuilder::kFloat64Ceil | MachineOperatorBuilder::kFloat64Ceil |
MachineOperatorBuilder::kFloat64RoundTruncate; MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kWord32ShiftIsSafe;
} }
return MachineOperatorBuilder::kNoFlags; return MachineOperatorBuilder::kNoFlags;
} }
......
...@@ -52,11 +52,13 @@ double ValueOfOperator<double>(const Operator* op) { ...@@ -52,11 +52,13 @@ double ValueOfOperator<double>(const Operator* op) {
class ReducerTester : public HandleAndZoneScope { class ReducerTester : public HandleAndZoneScope {
public: public:
explicit ReducerTester(int num_parameters = 0) explicit ReducerTester(
int num_parameters = 0,
MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags)
: isolate(main_isolate()), : isolate(main_isolate()),
binop(NULL), binop(NULL),
unop(NULL), unop(NULL),
machine(main_zone()), machine(main_zone(), kMachPtr, flags),
common(main_zone()), common(main_zone()),
graph(main_zone()), graph(main_zone()),
javascript(main_zone()), javascript(main_zone()),
...@@ -358,7 +360,36 @@ TEST(ReduceWord32Sar) { ...@@ -358,7 +360,36 @@ TEST(ReduceWord32Sar) {
} }
TEST(ReduceWord32Equal) { static void CheckJsShift(ReducerTester* R) {
DCHECK(R->machine.Word32ShiftIsSafe());
Node* x = R->Parameter(0);
Node* y = R->Parameter(1);
Node* thirty_one = R->Constant<int32_t>(0x1f);
Node* y_and_thirty_one =
R->graph.NewNode(R->machine.Word32And(), y, thirty_one);
// If the underlying machine shift instructions 'and' their right operand
// with 0x1f then: x << (y & 0x1f) => x << y
R->CheckFoldBinop(x, y, x, y_and_thirty_one);
}
TEST(ReduceJsShifts) {
ReducerTester R(0, MachineOperatorBuilder::kWord32ShiftIsSafe);
R.binop = R.machine.Word32Shl();
CheckJsShift(&R);
R.binop = R.machine.Word32Shr();
CheckJsShift(&R);
R.binop = R.machine.Word32Sar();
CheckJsShift(&R);
}
TEST(Word32Equal) {
ReducerTester R; ReducerTester R;
R.binop = R.machine.Word32Equal(); R.binop = R.machine.Word32Equal();
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var stdlib = {};
var foreign = {};
var heap = new ArrayBuffer(64 * 1024);
var rol = (function Module(stdlib, foreign, heap) {
"use asm";
function rol(x, y) {
x = x | 0;
y = y | 0;
return (x << y) | (x >>> (32 - y));
}
return { rol: rol };
})(stdlib, foreign, heap).rol;
assertEquals(10, rol(10, 0));
assertEquals(2, rol(1, 1));
assertEquals(0x40000000, rol(1, 30));
assertEquals(-0x80000000, rol(1, 31));
...@@ -573,23 +573,22 @@ TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) { ...@@ -573,23 +573,22 @@ TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) {
Node* value = Parameter(0); Node* value = Parameter(0);
Node* shift = Parameter(1); Node* shift = Parameter(1);
Node* shl = graph()->NewNode(machine()->Word32Shl(), value, shift); Node* shl = graph()->NewNode(machine()->Word32Shl(), value, shift);
Node* shr = graph()->NewNode( Node* sub = graph()->NewNode(machine()->Int32Sub(), Int32Constant(32), shift);
machine()->Word32Shr(), value, Node* shr = graph()->NewNode(machine()->Word32Shr(), value, sub);
graph()->NewNode(machine()->Int32Sub(), Int32Constant(32), shift));
// (x << y) | (x >> (32 - y)) => x ror y // (x << y) | (x >>> (32 - y)) => x ror (32 - y)
Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr); Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
Reduction reduction1 = Reduce(node1); Reduction reduction1 = Reduce(node1);
EXPECT_TRUE(reduction1.Changed()); EXPECT_TRUE(reduction1.Changed());
EXPECT_EQ(reduction1.replacement(), node1); EXPECT_EQ(reduction1.replacement(), node1);
EXPECT_THAT(reduction1.replacement(), IsWord32Ror(value, shift)); EXPECT_THAT(reduction1.replacement(), IsWord32Ror(value, sub));
// (x >> (32 - y)) | (x << y) => x ror y // (x >>> (32 - y)) | (x << y) => x ror y
Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl); Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
Reduction reduction2 = Reduce(node2); Reduction reduction2 = Reduce(node2);
EXPECT_TRUE(reduction2.Changed()); EXPECT_TRUE(reduction2.Changed());
EXPECT_EQ(reduction2.replacement(), node2); EXPECT_EQ(reduction2.replacement(), node2);
EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, shift)); EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, sub));
} }
...@@ -601,21 +600,21 @@ TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) { ...@@ -601,21 +600,21 @@ TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) {
Node* shr = Node* shr =
graph()->NewNode(machine()->Word32Shr(), value, Int32Constant(32 - k)); graph()->NewNode(machine()->Word32Shr(), value, Int32Constant(32 - k));
// (x << K) | (x >> ((32 - K) - y)) => x ror K // (x << K) | (x >>> ((32 - K) - y)) => x ror (32 - K)
Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr); Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
Reduction reduction1 = Reduce(node1); Reduction reduction1 = Reduce(node1);
EXPECT_TRUE(reduction1.Changed()); EXPECT_TRUE(reduction1.Changed());
EXPECT_EQ(reduction1.replacement(), node1); EXPECT_EQ(reduction1.replacement(), node1);
EXPECT_THAT(reduction1.replacement(), EXPECT_THAT(reduction1.replacement(),
IsWord32Ror(value, IsInt32Constant(k))); IsWord32Ror(value, IsInt32Constant(32 - k)));
// (x >> (32 - K)) | (x << K) => x ror K // (x >>> (32 - K)) | (x << K) => x ror K
Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl); Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
Reduction reduction2 = Reduce(node2); Reduction reduction2 = Reduce(node2);
EXPECT_TRUE(reduction2.Changed()); EXPECT_TRUE(reduction2.Changed());
EXPECT_EQ(reduction2.replacement(), node2); EXPECT_EQ(reduction2.replacement(), node2);
EXPECT_THAT(reduction2.replacement(), EXPECT_THAT(reduction2.replacement(),
IsWord32Ror(value, IsInt32Constant(k))); IsWord32Ror(value, IsInt32Constant(32 - k)));
} }
} }
......
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