Commit dcf193f1 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Strength reduction for inline comparisons.

Perform strength reduction on machine operators with inline comparisons:

  CMP & 1 => CMP
  1 & CMP => CMP
  CMP << 31 >> 31 => CMP

Also strength reduce the following constructs:

  x + (0 - y) => x - y
  (0 - y) + x => x - y

R=dcarney@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#26817}
parent b33f552f
...@@ -589,6 +589,7 @@ source_set("v8_base") { ...@@ -589,6 +589,7 @@ source_set("v8_base") {
"src/compiler/node-cache.h", "src/compiler/node-cache.h",
"src/compiler/node-marker.cc", "src/compiler/node-marker.cc",
"src/compiler/node-marker.h", "src/compiler/node-marker.h",
"src/compiler/node-matchers.cc",
"src/compiler/node-matchers.h", "src/compiler/node-matchers.h",
"src/compiler/node-properties.cc", "src/compiler/node-properties.cc",
"src/compiler/node-properties.h", "src/compiler/node-properties.h",
......
...@@ -160,29 +160,8 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { ...@@ -160,29 +160,8 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
} }
return ReduceWord32Shifts(node); return ReduceWord32Shifts(node);
} }
case IrOpcode::kWord32Sar: { case IrOpcode::kWord32Sar:
Int32BinopMatcher m(node); return ReduceWord32Sar(node);
if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x
if (m.IsFoldable()) { // K >> K => K
return ReplaceInt32(m.left().Value() >> m.right().Value());
}
if (m.left().IsWord32Shl()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.left().IsLoad()) {
LoadRepresentation const rep =
OpParameter<LoadRepresentation>(mleft.left().node());
if (m.right().Is(24) && mleft.right().Is(24) && rep == kMachInt8) {
// Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
return Replace(mleft.left().node());
}
if (m.right().Is(16) && mleft.right().Is(16) && rep == kMachInt16) {
// Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
return Replace(mleft.left().node());
}
}
}
return ReduceWord32Shifts(node);
}
case IrOpcode::kWord32Ror: { case IrOpcode::kWord32Ror: {
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x
...@@ -471,6 +450,25 @@ Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) { ...@@ -471,6 +450,25 @@ Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) + return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
bit_cast<uint32_t>(m.right().Value())); bit_cast<uint32_t>(m.right().Value()));
} }
if (m.left().IsInt32Sub()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.left().Is(0)) { // (0 - x) + y => y - x
node->set_op(machine()->Int32Sub());
node->ReplaceInput(0, m.right().node());
node->ReplaceInput(1, mleft.right().node());
Reduction const reduction = ReduceInt32Sub(node);
return reduction.Changed() ? reduction : Changed(node);
}
}
if (m.right().IsInt32Sub()) {
Int32BinopMatcher mright(m.right().node());
if (mright.left().Is(0)) { // y + (0 - x) => y - x
node->set_op(machine()->Int32Sub());
node->ReplaceInput(1, mright.right().node());
Reduction const reduction = ReduceInt32Sub(node);
return reduction.Changed() ? reduction : Changed(node);
}
}
return NoChange(); return NoChange();
} }
...@@ -784,11 +782,48 @@ Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) { ...@@ -784,11 +782,48 @@ Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
} }
Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) {
Int32BinopMatcher m(node);
if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x
if (m.IsFoldable()) { // K >> K => K
return ReplaceInt32(m.left().Value() >> m.right().Value());
}
if (m.left().IsWord32Shl()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.left().IsComparison()) {
if (m.right().Is(31) && mleft.right().Is(31)) {
// Comparison << 31 >> 31 => 0 - Comparison
node->set_op(machine()->Int32Sub());
node->ReplaceInput(0, Int32Constant(0));
node->ReplaceInput(1, mleft.left().node());
Reduction const reduction = ReduceInt32Sub(node);
return reduction.Changed() ? reduction : Changed(node);
}
} else if (mleft.left().IsLoad()) {
LoadRepresentation const rep =
OpParameter<LoadRepresentation>(mleft.left().node());
if (m.right().Is(24) && mleft.right().Is(24) && rep == kMachInt8) {
// Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
return Replace(mleft.left().node());
}
if (m.right().Is(16) && mleft.right().Is(16) && rep == kMachInt16) {
// Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
return Replace(mleft.left().node());
}
}
}
return ReduceWord32Shifts(node);
}
Reduction MachineOperatorReducer::ReduceWord32And(Node* node) { Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
DCHECK_EQ(IrOpcode::kWord32And, node->opcode()); DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
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
if (m.left().IsComparison() && m.right().Is(1)) { // CMP & 1 => CMP
return Replace(m.left().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());
} }
......
...@@ -75,6 +75,7 @@ class MachineOperatorReducer FINAL : public Reducer { ...@@ -75,6 +75,7 @@ class MachineOperatorReducer FINAL : public Reducer {
Reduction ReduceProjection(size_t index, Node* node); Reduction ReduceProjection(size_t index, Node* node);
Reduction ReduceWord32Shifts(Node* node); Reduction ReduceWord32Shifts(Node* node);
Reduction ReduceWord32Shl(Node* node); Reduction ReduceWord32Shl(Node* node);
Reduction ReduceWord32Sar(Node* node);
Reduction ReduceWord32And(Node* node); Reduction ReduceWord32And(Node* node);
Reduction ReduceWord32Or(Node* node); Reduction ReduceWord32Or(Node* node);
......
// Copyright 2015 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.
#include "src/compiler/node-matchers.h"
namespace v8 {
namespace internal {
namespace compiler {
bool NodeMatcher::IsComparison() const {
return IrOpcode::IsComparisonOpcode(opcode());
}
} // namespace compiler
} // namespace internal
} // namespace v8
...@@ -28,6 +28,8 @@ struct NodeMatcher { ...@@ -28,6 +28,8 @@ struct NodeMatcher {
} }
Node* InputAt(int index) const { return node()->InputAt(index); } Node* InputAt(int index) const { return node()->InputAt(index); }
bool IsComparison() const;
#define DEFINE_IS_OPCODE(Opcode) \ #define DEFINE_IS_OPCODE(Opcode) \
bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; } bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
ALL_OP_LIST(DEFINE_IS_OPCODE) ALL_OP_LIST(DEFINE_IS_OPCODE)
......
...@@ -140,113 +140,119 @@ ...@@ -140,113 +140,119 @@
JS_OTHER_OP_LIST(V) JS_OTHER_OP_LIST(V)
// Opcodes for VirtuaMachine-level operators. // Opcodes for VirtuaMachine-level operators.
#define SIMPLIFIED_OP_LIST(V) \ #define SIMPLIFIED_COMPARE_BINOP_LIST(V) \
V(AnyToBoolean) \ V(NumberEqual) \
V(BooleanNot) \ V(NumberLessThan) \
V(BooleanToNumber) \ V(NumberLessThanOrEqual) \
V(NumberEqual) \ V(ReferenceEqual) \
V(NumberLessThan) \ V(StringEqual) \
V(NumberLessThanOrEqual) \ V(StringLessThan) \
V(NumberAdd) \ V(StringLessThanOrEqual)
V(NumberSubtract) \
V(NumberMultiply) \ #define SIMPLIFIED_OP_LIST(V) \
V(NumberDivide) \ SIMPLIFIED_COMPARE_BINOP_LIST(V) \
V(NumberModulus) \ V(AnyToBoolean) \
V(NumberToInt32) \ V(BooleanNot) \
V(NumberToUint32) \ V(BooleanToNumber) \
V(PlainPrimitiveToNumber) \ V(NumberAdd) \
V(ReferenceEqual) \ V(NumberSubtract) \
V(StringEqual) \ V(NumberMultiply) \
V(StringLessThan) \ V(NumberDivide) \
V(StringLessThanOrEqual) \ V(NumberModulus) \
V(StringAdd) \ V(NumberToInt32) \
V(ChangeTaggedToInt32) \ V(NumberToUint32) \
V(ChangeTaggedToUint32) \ V(PlainPrimitiveToNumber) \
V(ChangeTaggedToFloat64) \ V(StringAdd) \
V(ChangeInt32ToTagged) \ V(ChangeTaggedToInt32) \
V(ChangeUint32ToTagged) \ V(ChangeTaggedToUint32) \
V(ChangeFloat64ToTagged) \ V(ChangeTaggedToFloat64) \
V(ChangeBoolToBit) \ V(ChangeInt32ToTagged) \
V(ChangeBitToBool) \ V(ChangeUint32ToTagged) \
V(LoadField) \ V(ChangeFloat64ToTagged) \
V(LoadBuffer) \ V(ChangeBoolToBit) \
V(LoadElement) \ V(ChangeBitToBool) \
V(StoreField) \ V(LoadField) \
V(StoreBuffer) \ V(LoadBuffer) \
V(StoreElement) \ V(LoadElement) \
V(ObjectIsSmi) \ V(StoreField) \
V(StoreBuffer) \
V(StoreElement) \
V(ObjectIsSmi) \
V(ObjectIsNonNegativeSmi) V(ObjectIsNonNegativeSmi)
// Opcodes for Machine-level operators. // Opcodes for Machine-level operators.
#define MACHINE_OP_LIST(V) \ #define MACHINE_COMPARE_BINOP_LIST(V) \
V(Load) \ V(Word32Equal) \
V(Store) \ V(Word64Equal) \
V(Word32And) \ V(Int32LessThan) \
V(Word32Or) \ V(Int32LessThanOrEqual) \
V(Word32Xor) \ V(Uint32LessThan) \
V(Word32Shl) \ V(Uint32LessThanOrEqual) \
V(Word32Shr) \ V(Int64LessThan) \
V(Word32Sar) \ V(Int64LessThanOrEqual) \
V(Word32Ror) \ V(Uint64LessThan) \
V(Word32Equal) \ V(Float64Equal) \
V(Word64And) \ V(Float64LessThan) \
V(Word64Or) \ V(Float64LessThanOrEqual)
V(Word64Xor) \
V(Word64Shl) \ #define MACHINE_OP_LIST(V) \
V(Word64Shr) \ MACHINE_COMPARE_BINOP_LIST(V) \
V(Word64Sar) \ V(Load) \
V(Word64Ror) \ V(Store) \
V(Word64Equal) \ V(Word32And) \
V(Int32Add) \ V(Word32Or) \
V(Int32AddWithOverflow) \ V(Word32Xor) \
V(Int32Sub) \ V(Word32Shl) \
V(Int32SubWithOverflow) \ V(Word32Shr) \
V(Int32Mul) \ V(Word32Sar) \
V(Int32MulHigh) \ V(Word32Ror) \
V(Int32Div) \ V(Word64And) \
V(Int32Mod) \ V(Word64Or) \
V(Int32LessThan) \ V(Word64Xor) \
V(Int32LessThanOrEqual) \ V(Word64Shl) \
V(Uint32Div) \ V(Word64Shr) \
V(Uint32LessThan) \ V(Word64Sar) \
V(Uint32LessThanOrEqual) \ V(Word64Ror) \
V(Uint32Mod) \ V(Int32Add) \
V(Uint32MulHigh) \ V(Int32AddWithOverflow) \
V(Int64Add) \ V(Int32Sub) \
V(Int64Sub) \ V(Int32SubWithOverflow) \
V(Int64Mul) \ V(Int32Mul) \
V(Int64Div) \ V(Int32MulHigh) \
V(Int64Mod) \ V(Int32Div) \
V(Int64LessThan) \ V(Int32Mod) \
V(Int64LessThanOrEqual) \ V(Uint32Div) \
V(Uint64Div) \ V(Uint32Mod) \
V(Uint64LessThan) \ V(Uint32MulHigh) \
V(Uint64Mod) \ V(Int64Add) \
V(ChangeFloat32ToFloat64) \ V(Int64Sub) \
V(ChangeFloat64ToInt32) \ V(Int64Mul) \
V(ChangeFloat64ToUint32) \ V(Int64Div) \
V(ChangeInt32ToFloat64) \ V(Int64Mod) \
V(ChangeInt32ToInt64) \ V(Uint64Div) \
V(ChangeUint32ToFloat64) \ V(Uint64Mod) \
V(ChangeUint32ToUint64) \ V(ChangeFloat32ToFloat64) \
V(TruncateFloat64ToFloat32) \ V(ChangeFloat64ToInt32) \
V(TruncateFloat64ToInt32) \ V(ChangeFloat64ToUint32) \
V(TruncateInt64ToInt32) \ V(ChangeInt32ToFloat64) \
V(Float64Add) \ V(ChangeInt32ToInt64) \
V(Float64Sub) \ V(ChangeUint32ToFloat64) \
V(Float64Mul) \ V(ChangeUint32ToUint64) \
V(Float64Div) \ V(TruncateFloat64ToFloat32) \
V(Float64Mod) \ V(TruncateFloat64ToInt32) \
V(Float64Sqrt) \ V(TruncateInt64ToInt32) \
V(Float64Equal) \ V(Float64Add) \
V(Float64LessThan) \ V(Float64Sub) \
V(Float64LessThanOrEqual) \ V(Float64Mul) \
V(Float64Floor) \ V(Float64Div) \
V(Float64Ceil) \ V(Float64Mod) \
V(Float64RoundTruncate) \ V(Float64Sqrt) \
V(Float64RoundTiesAway) \ V(Float64Floor) \
V(LoadStackPointer) \ V(Float64Ceil) \
V(CheckedLoad) \ V(Float64RoundTruncate) \
V(Float64RoundTiesAway) \
V(LoadStackPointer) \
V(CheckedLoad) \
V(CheckedStore) V(CheckedStore)
#define VALUE_OP_LIST(V) \ #define VALUE_OP_LIST(V) \
...@@ -308,6 +314,13 @@ class IrOpcode { ...@@ -308,6 +314,13 @@ class IrOpcode {
static bool IsMergeOpcode(Value value) { static bool IsMergeOpcode(Value value) {
return value == kMerge || value == kLoop; return value == kMerge || value == kLoop;
} }
// Returns true if opcode for comparison operator.
static bool IsComparisonOpcode(Value value) {
return (kJSEqual <= value && value <= kJSGreaterThanOrEqual) ||
(kNumberEqual <= value && value <= kStringLessThanOrEqual) ||
(kWord32Equal <= value && value <= kFloat64LessThanOrEqual);
}
}; };
} // namespace compiler } // namespace compiler
......
...@@ -233,6 +233,27 @@ const uint32_t kUint32Values[] = { ...@@ -233,6 +233,27 @@ const uint32_t kUint32Values[] = {
0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff, 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff}; 0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
struct ComparisonBinaryOperator {
const Operator* (MachineOperatorBuilder::*constructor)();
const char* constructor_name;
};
std::ostream& operator<<(std::ostream& os,
ComparisonBinaryOperator const& cbop) {
return os << cbop.constructor_name;
}
const ComparisonBinaryOperator kComparisonBinaryOperators[] = {
#define OPCODE(Opcode) \
{ &MachineOperatorBuilder::Opcode, #Opcode } \
,
MACHINE_COMPARE_BINOP_LIST(OPCODE)
#undef OPCODE
};
} // namespace } // namespace
...@@ -632,6 +653,27 @@ TEST_F(MachineOperatorReducerTest, ...@@ -632,6 +653,27 @@ TEST_F(MachineOperatorReducerTest,
} }
TEST_F(MachineOperatorReducerTest, Word32AndWithComparisonAndConstantOne) {
Node* const p0 = Parameter(0);
Node* const p1 = Parameter(1);
TRACED_FOREACH(ComparisonBinaryOperator, cbop, kComparisonBinaryOperators) {
Node* cmp = graph()->NewNode((machine()->*cbop.constructor)(), p0, p1);
// cmp & 1 => cmp
Reduction const r1 =
Reduce(graph()->NewNode(machine()->Word32And(), cmp, Int32Constant(1)));
ASSERT_TRUE(r1.Changed());
EXPECT_EQ(cmp, r1.replacement());
// 1 & cmp => cmp
Reduction const r2 =
Reduce(graph()->NewNode(machine()->Word32And(), Int32Constant(1), cmp));
ASSERT_TRUE(r2.Changed());
EXPECT_EQ(cmp, r2.replacement());
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Word32Xor // Word32Xor
...@@ -773,6 +815,24 @@ TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) { ...@@ -773,6 +815,24 @@ TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) {
// Word32Sar // Word32Sar
TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndComparison) {
Node* const p0 = Parameter(0);
Node* const p1 = Parameter(1);
TRACED_FOREACH(ComparisonBinaryOperator, cbop, kComparisonBinaryOperators) {
Node* cmp = graph()->NewNode((machine()->*cbop.constructor)(), p0, p1);
// cmp << 31 >> 31 => 0 - cmp
Reduction const r = Reduce(graph()->NewNode(
machine()->Word32Sar(),
graph()->NewNode(machine()->Word32Shl(), cmp, Int32Constant(31)),
Int32Constant(31)));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), cmp));
}
}
TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) { TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) {
Node* const p0 = Parameter(0); Node* const p0 = Parameter(0);
Node* const p1 = Parameter(1); Node* const p1 = Parameter(1);
...@@ -1189,6 +1249,28 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) { ...@@ -1189,6 +1249,28 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
} }
// -----------------------------------------------------------------------------
// Int32Add
TEST_F(MachineOperatorReducerTest, Int32AddWithInt32SubWithConstantZero) {
Node* const p0 = Parameter(0);
Node* const p1 = Parameter(1);
Reduction const r1 = Reduce(graph()->NewNode(
machine()->Int32Add(),
graph()->NewNode(machine()->Int32Sub(), Int32Constant(0), p0), p1));
ASSERT_TRUE(r1.Changed());
EXPECT_THAT(r1.replacement(), IsInt32Sub(p1, p0));
Reduction const r2 = Reduce(graph()->NewNode(
machine()->Int32Add(), p0,
graph()->NewNode(machine()->Int32Sub(), Int32Constant(0), p1)));
ASSERT_TRUE(r2.Changed());
EXPECT_THAT(r2.replacement(), IsInt32Sub(p0, p1));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Int32AddWithOverflow // Int32AddWithOverflow
......
...@@ -64,6 +64,21 @@ bool IsConstantOpcode(IrOpcode::Value opcode) { ...@@ -64,6 +64,21 @@ bool IsConstantOpcode(IrOpcode::Value opcode) {
} }
bool IsComparisonOpcode(IrOpcode::Value opcode) {
switch (opcode) {
#define OPCODE(Opcode) \
case IrOpcode::k##Opcode: \
return true;
JS_COMPARE_BINOP_LIST(OPCODE)
SIMPLIFIED_COMPARE_BINOP_LIST(OPCODE)
MACHINE_COMPARE_BINOP_LIST(OPCODE)
#undef OPCODE
default:
return false;
}
}
const IrOpcode::Value kInvalidOpcode = static_cast<IrOpcode::Value>(123456789); const IrOpcode::Value kInvalidOpcode = static_cast<IrOpcode::Value>(123456789);
} // namespace } // namespace
...@@ -109,6 +124,16 @@ TEST(IrOpcodeTest, IsConstantOpcode) { ...@@ -109,6 +124,16 @@ TEST(IrOpcodeTest, IsConstantOpcode) {
} }
TEST(IrOpcodeTest, IsComparisonOpcode) {
EXPECT_FALSE(IrOpcode::IsComparisonOpcode(kInvalidOpcode));
#define OPCODE(Opcode) \
EXPECT_EQ(IsComparisonOpcode(IrOpcode::k##Opcode), \
IrOpcode::IsComparisonOpcode(IrOpcode::k##Opcode));
ALL_OP_LIST(OPCODE)
#undef OPCODE
}
TEST(IrOpcodeTest, Mnemonic) { TEST(IrOpcodeTest, Mnemonic) {
EXPECT_STREQ("UnknownOpcode", IrOpcode::Mnemonic(kInvalidOpcode)); EXPECT_STREQ("UnknownOpcode", IrOpcode::Mnemonic(kInvalidOpcode));
#define OPCODE(Opcode) \ #define OPCODE(Opcode) \
......
...@@ -497,6 +497,7 @@ ...@@ -497,6 +497,7 @@
'../../src/compiler/node-cache.h', '../../src/compiler/node-cache.h',
'../../src/compiler/node-marker.cc', '../../src/compiler/node-marker.cc',
'../../src/compiler/node-marker.h', '../../src/compiler/node-marker.h',
'../../src/compiler/node-matchers.cc',
'../../src/compiler/node-matchers.h', '../../src/compiler/node-matchers.h',
'../../src/compiler/node-properties.cc', '../../src/compiler/node-properties.cc',
'../../src/compiler/node-properties.h', '../../src/compiler/node-properties.h',
......
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