"src/compiler/node-aux-data.h",
"src/compiler/node-cache.cc",
"src/compiler/node-cache.h",
+ "src/compiler/node-matchers.cc",
"src/compiler/node-matchers.h",
"src/compiler/node-properties-inl.h",
"src/compiler/node-properties.h",
--- /dev/null
+// 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.
+
+#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+const int ScaleFactorMatcher::kMatchedFactors[] = {1, 2, 4, 8};
+
+
+ScaleFactorMatcher::ScaleFactorMatcher(Node* node)
+ : NodeMatcher(node), left_(NULL), power_(0) {
+ if (opcode() != IrOpcode::kInt32Mul) return;
+ // TODO(dcarney): should test 64 bit ints as well.
+ Int32BinopMatcher m(this->node());
+ if (!m.right().HasValue()) return;
+ int32_t value = m.right().Value();
+ switch (value) {
+ case 8:
+ power_++; // Fall through.
+ case 4:
+ power_++; // Fall through.
+ case 2:
+ power_++; // Fall through.
+ case 1:
+ break;
+ default:
+ return;
+ }
+ left_ = m.left().node();
+}
+
+
+IndexAndDisplacementMatcher::IndexAndDisplacementMatcher(Node* node)
+ : NodeMatcher(node), index_node_(node), displacement_(0), power_(0) {
+ if (opcode() == IrOpcode::kInt32Add) {
+ Int32BinopMatcher m(this->node());
+ if (m.right().HasValue()) {
+ displacement_ = m.right().Value();
+ index_node_ = m.left().node();
+ }
+ }
+ // Test scale factor.
+ ScaleFactorMatcher scale_matcher(index_node_);
+ if (scale_matcher.Matches()) {
+ index_node_ = scale_matcher.Left();
+ power_ = scale_matcher.Power();
+ }
+}
+
+
+const int LeaMultiplyMatcher::kMatchedFactors[7] = {1, 2, 3, 4, 5, 8, 9};
+
+
+LeaMultiplyMatcher::LeaMultiplyMatcher(Node* node)
+ : NodeMatcher(node), left_(NULL), power_(0), displacement_(0) {
+ if (opcode() != IrOpcode::kInt32Mul && opcode() != IrOpcode::kInt64Mul) {
+ return;
+ }
+ int64_t value;
+ Node* left = NULL;
+ {
+ Int32BinopMatcher m(this->node());
+ if (m.right().HasValue()) {
+ value = m.right().Value();
+ left = m.left().node();
+ } else {
+ Int64BinopMatcher m(this->node());
+ if (m.right().HasValue()) {
+ value = m.right().Value();
+ left = m.left().node();
+ } else {
+ return;
+ }
+ }
+ }
+ switch (value) {
+ case 9:
+ case 8:
+ power_++; // Fall through.
+ case 5:
+ case 4:
+ power_++; // Fall through.
+ case 3:
+ case 2:
+ power_++; // Fall through.
+ case 1:
+ break;
+ default:
+ return;
+ }
+ if (!base::bits::IsPowerOfTwo64(value)) {
+ displacement_ = 1;
+ }
+ left_ = left;
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
// Matches nodes of form [x * N] for N in {1,2,4,8}
class ScaleFactorMatcher : public NodeMatcher {
public:
- explicit ScaleFactorMatcher(Node* node)
- : NodeMatcher(node), left_(NULL), power_(0) {
- Match();
- }
+ static const int kMatchedFactors[4];
+
+ explicit ScaleFactorMatcher(Node* node);
- bool Matches() { return left_ != NULL; }
- int Power() {
+ bool Matches() const { return left_ != NULL; }
+ int Power() const {
DCHECK(Matches());
return power_;
}
- Node* Left() {
+ Node* Left() const {
DCHECK(Matches());
return left_;
}
private:
- void Match() {
- if (opcode() != IrOpcode::kInt32Mul) return;
- Int32BinopMatcher m(node());
- if (!m.right().HasValue()) return;
- int32_t value = m.right().Value();
- switch (value) {
- case 8:
- power_++; // Fall through.
- case 4:
- power_++; // Fall through.
- case 2:
- power_++; // Fall through.
- case 1:
- break;
- default:
- return;
- }
- left_ = m.left().node();
- }
-
Node* left_;
int power_;
};
// for N in {1,2,4,8} and K int32_t
class IndexAndDisplacementMatcher : public NodeMatcher {
public:
- explicit IndexAndDisplacementMatcher(Node* node)
- : NodeMatcher(node), index_node_(node), displacement_(0), power_(0) {
- Match();
- }
+ explicit IndexAndDisplacementMatcher(Node* node);
- Node* index_node() { return index_node_; }
- int displacement() { return displacement_; }
- int power() { return power_; }
+ Node* index_node() const { return index_node_; }
+ int displacement() const { return displacement_; }
+ int power() const { return power_; }
private:
- void Match() {
- if (opcode() == IrOpcode::kInt32Add) {
- // Assume reduction has put constant on the right.
- Int32BinopMatcher m(node());
- if (m.right().HasValue()) {
- displacement_ = m.right().Value();
- index_node_ = m.left().node();
- }
- }
- // Test scale factor.
- ScaleFactorMatcher scale_matcher(index_node_);
- if (scale_matcher.Matches()) {
- index_node_ = scale_matcher.Left();
- power_ = scale_matcher.Power();
- }
- }
-
Node* index_node_;
int displacement_;
int power_;
};
+// Fairly intel-specify node matcher used for matching multiplies that can be
+// transformed to lea instructions.
+// Matches nodes of form:
+// [x * N]
+// for N in {1,2,3,4,5,8,9}
+class LeaMultiplyMatcher : public NodeMatcher {
+ public:
+ static const int kMatchedFactors[7];
+
+ explicit LeaMultiplyMatcher(Node* node);
+
+ bool Matches() const { return left_ != NULL; }
+ int Power() const {
+ DCHECK(Matches());
+ return power_;
+ }
+ Node* Left() const {
+ DCHECK(Matches());
+ return left_;
+ }
+ // Displacement will be either 0 or 1.
+ int32_t Displacement() const {
+ DCHECK(Matches());
+ return displacement_;
+ }
+
+ private:
+ Node* left_;
+ int power_;
+ int displacement_;
+};
+
+
} // namespace compiler
} // namespace internal
} // namespace v8
__ movsd(operand, i.InputDoubleRegister(index));
}
break;
+ case kX64Lea32:
+ __ leal(i.OutputRegister(), i.MemoryOperand());
+ break;
+ case kX64Lea:
+ __ leaq(i.OutputRegister(), i.MemoryOperand());
+ break;
case kX64Push:
if (HasImmediateInput(instr, 0)) {
__ pushq(i.InputImmediate(0));
V(X64Movq) \
V(X64Movsd) \
V(X64Movss) \
+ V(X64Lea32) \
+ V(X64Lea) \
V(X64Push) \
V(X64StoreWriteBarrier)
// found in the LICENSE file.
#include "src/compiler/instruction-selector-unittest.h"
+#include "src/compiler/node-matchers.h"
namespace v8 {
namespace internal {
Node* non_zero;
Node* base_reg; // opaque value to generate base as register
Node* index_reg; // opaque value to generate index as register
- Node* scales[4];
+ Node* scales[arraysize(ScaleFactorMatcher::kMatchedFactors)];
StreamBuilder* m;
void Reset() {
non_zero = m->Int32Constant(127);
base_reg = m->Parameter(0);
index_reg = m->Parameter(0);
-
- scales[0] = m->Int32Constant(1);
- scales[1] = m->Int32Constant(2);
- scales[2] = m->Int32Constant(4);
- scales[3] = m->Int32Constant(8);
+ for (size_t i = 0; i < arraysize(ScaleFactorMatcher::kMatchedFactors);
+ ++i) {
+ scales[i] = m->Int32Constant(ScaleFactorMatcher::kMatchedFactors[i]);
+ }
}
};
}
}
+
+// -----------------------------------------------------------------------------
+// Multiplication.
+
+namespace {
+
+struct MultParam {
+ int value;
+ bool lea_expected;
+ AddressingMode addressing_mode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MultParam& m) {
+ OStringStream ost;
+ ost << m.value << "." << m.lea_expected << "." << m.addressing_mode;
+ return os << ost.c_str();
+}
+
+
+const MultParam kMultParams[] = {{-1, false, kMode_None},
+ {0, false, kMode_None},
+ {1, true, kMode_M1},
+ {2, true, kMode_M2},
+ {3, true, kMode_MR2},
+ {4, true, kMode_M4},
+ {5, true, kMode_MR4},
+ {6, false, kMode_None},
+ {7, false, kMode_None},
+ {8, true, kMode_M8},
+ {9, true, kMode_MR8},
+ {10, false, kMode_None},
+ {11, false, kMode_None}};
+
+} // namespace
+
+
+typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest;
+
+
+static unsigned InputCountForLea(AddressingMode mode) {
+ switch (mode) {
+ case kMode_MR1:
+ case kMode_MR2:
+ case kMode_MR4:
+ case kMode_MR8:
+ return 2U;
+ case kMode_M1:
+ case kMode_M2:
+ case kMode_M4:
+ case kMode_M8:
+ return 1U;
+ default:
+ UNREACHABLE();
+ return 0U;
+ }
+}
+
+
+TEST_P(InstructionSelectorMultTest, Mult32) {
+ const MultParam m_param = GetParam();
+ StreamBuilder m(this, kMachInt32, kMachInt32);
+ Node* param = m.Parameter(0);
+ Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value));
+ m.Return(mult);
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode());
+ if (m_param.lea_expected) {
+ EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+ ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount());
+ } else {
+ EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ }
+ EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_P(InstructionSelectorMultTest, Mult64) {
+ const MultParam m_param = GetParam();
+ StreamBuilder m(this, kMachInt64, kMachInt64);
+ Node* param = m.Parameter(0);
+ Node* mult = m.Int64Mul(param, m.Int64Constant(m_param.value));
+ m.Return(mult);
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode());
+ if (m_param.lea_expected) {
+ EXPECT_EQ(kX64Lea, s[0]->arch_opcode());
+ ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount());
+ EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(0)));
+ } else {
+ EXPECT_EQ(kX64Imul, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ // TODO(dcarney): why is this happening?
+ EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(1)));
+ }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
+ ::testing::ValuesIn(kMultParams));
+
} // namespace compiler
} // namespace internal
} // namespace v8
};
+// Get the AddressingMode of scale factor N from the AddressingMode of scale
+// factor 1.
+static AddressingMode AdjustAddressingMode(AddressingMode base_mode,
+ int power) {
+ DCHECK(0 <= power && power < 4);
+ return static_cast<AddressingMode>(static_cast<int>(base_mode) + power);
+}
+
+
class AddressingModeMatcher {
public:
AddressingModeMatcher(X64OperandGenerator* g, Node* base, Node* index)
}
}
// Adjust mode to actual scale factor.
- mode_ = GetMode(mode_, matcher.power());
+ mode_ = AdjustAddressingMode(mode_, matcher.power());
}
DCHECK_NE(kMode_None, mode_);
}
- AddressingMode GetMode(AddressingMode one, int power) {
- return static_cast<AddressingMode>(static_cast<int>(one) + power);
- }
-
size_t SetInputs(InstructionOperand** inputs) {
size_t input_count = 0;
// Compute inputs_ and input_count.
static void VisitMul(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
X64OperandGenerator g(selector);
- Int32BinopMatcher m(node);
- Node* left = m.left().node();
- Node* right = m.right().node();
- if (g.CanBeImmediate(right)) {
- selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
- g.UseImmediate(right));
+ LeaMultiplyMatcher lea(node);
+ // Try to match lea.
+ if (lea.Matches()) {
+ switch (opcode) {
+ case kX64Imul32:
+ opcode = kX64Lea32;
+ break;
+ case kX64Imul:
+ opcode = kX64Lea;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ AddressingMode mode;
+ size_t input_count;
+ InstructionOperand* left = g.UseRegister(lea.Left());
+ InstructionOperand* inputs[] = {left, left};
+ if (lea.Displacement() != 0) {
+ input_count = 2;
+ mode = kMode_MR1;
+ } else {
+ input_count = 1;
+ mode = kMode_M1;
+ }
+ mode = AdjustAddressingMode(mode, lea.Power());
+ InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
+ selector->Emit(opcode | AddressingModeField::encode(mode), 1, outputs,
+ input_count, inputs);
} else {
- if (g.CanBeBetterLeftOperand(right)) {
- std::swap(left, right);
+ Int32BinopMatcher m(node);
+ Node* left = m.left().node();
+ Node* right = m.right().node();
+ if (g.CanBeImmediate(right)) {
+ selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
+ g.UseImmediate(right));
+ } else {
+ if (g.CanBeBetterLeftOperand(right)) {
+ std::swap(left, right);
+ }
+ selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
+ g.Use(right));
}
- selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
- g.Use(right));
}
}
'../../src/compiler/node-aux-data.h',
'../../src/compiler/node-cache.cc',
'../../src/compiler/node-cache.h',
+ '../../src/compiler/node-matchers.cc',
'../../src/compiler/node-matchers.h',
'../../src/compiler/node-properties-inl.h',
'../../src/compiler/node-properties.h',