Commit 574f6fe1 authored by danno's avatar danno Committed by Commit bot

[turbofan] Support subtraction displacements in BaseWithIndexAndDisplacementMatcher

Previously, the following schedule fragment:

 1: Parameter[0](0)
 2: Parameter[1](0)
 7: Int32Constant[1]
 8: Int32Sub(2, 7)
 9: Load[kRepTagged|kTypeAny](1, 8)

would generate the following code (on ia32):

 mov eax,[ebp+0x8]
 mov ecx,[ebp+0xc]
 sub eax,0x1
 mov eax,[eax+ecx*1]

Now it generates:

 mov eax,[ebp+0x8]
 mov ecx,[ebp+0xc]
 mov eax,[eax+ecx*1-1]

Similar pattern matching also now works on x64.

BUG=v8:5192
LOG=N

Review-Url: https://codereview.chromium.org/2137323003
Cr-Commit-Position: refs/heads/master@{#37701}
parent fd420203
......@@ -82,12 +82,16 @@ class IA32OperandGenerator final : public OperandGenerator {
AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
Node* displacement_node,
DisplacementMode displacement_mode,
InstructionOperand inputs[],
size_t* input_count) {
AddressingMode mode = kMode_MRI;
int32_t displacement = (displacement_node == nullptr)
? 0
: OpParameter<int32_t>(displacement_node);
if (displacement_mode == kNegativeDisplacement) {
displacement = -displacement;
}
if (base != nullptr) {
if (base->opcode() == IrOpcode::kInt32Constant) {
displacement += OpParameter<int32_t>(base);
......@@ -145,8 +149,9 @@ class IA32OperandGenerator final : public OperandGenerator {
BaseWithIndexAndDisplacement32Matcher m(node, true);
DCHECK(m.matches());
if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
m.displacement(), inputs, input_count);
return GenerateMemoryOperandInputs(
m.index(), m.scale(), m.base(), m.displacement(),
m.displacement_mode(), inputs, input_count);
} else {
inputs[(*input_count)++] = UseRegister(node->InputAt(0));
inputs[(*input_count)++] = UseRegister(node->InputAt(1));
......@@ -577,12 +582,14 @@ void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
}
void EmitLea(InstructionSelector* selector, Node* result, Node* index,
int scale, Node* base, Node* displacement) {
int scale, Node* base, Node* displacement,
DisplacementMode displacement_mode) {
IA32OperandGenerator g(selector);
InstructionOperand inputs[4];
size_t input_count = 0;
AddressingMode mode = g.GenerateMemoryOperandInputs(
index, scale, base, displacement, inputs, &input_count);
AddressingMode mode =
g.GenerateMemoryOperandInputs(index, scale, base, displacement,
displacement_mode, inputs, &input_count);
DCHECK_NE(0u, input_count);
DCHECK_GE(arraysize(inputs), input_count);
......@@ -603,7 +610,7 @@ void InstructionSelector::VisitWord32Shl(Node* node) {
if (m.matches()) {
Node* index = node->InputAt(0);
Node* base = m.power_of_two_plus_one() ? index : nullptr;
EmitLea(this, node, index, m.scale(), base, nullptr);
EmitLea(this, node, index, m.scale(), base, nullptr, kPositiveDisplacement);
return;
}
VisitShift(this, node, kIA32Shl);
......@@ -743,7 +750,8 @@ void InstructionSelector::VisitInt32Add(Node* node) {
InstructionOperand inputs[4];
size_t input_count = 0;
AddressingMode mode = g.GenerateMemoryOperandInputs(
m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
m.index(), m.scale(), m.base(), m.displacement(), m.displacement_mode(),
inputs, &input_count);
DCHECK_NE(0u, input_count);
DCHECK_GE(arraysize(inputs), input_count);
......@@ -777,7 +785,7 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
if (m.matches()) {
Node* index = node->InputAt(0);
Node* base = m.power_of_two_plus_one() ? index : nullptr;
EmitLea(this, node, index, m.scale(), base, nullptr);
EmitLea(this, node, index, m.scale(), base, nullptr, kPositiveDisplacement);
return;
}
IA32OperandGenerator g(this);
......
......@@ -143,6 +143,10 @@ class OperandGenerator {
return sequence()->AddImmediate(ToConstant(node));
}
InstructionOperand UseNegatedImmediate(Node* node) {
return sequence()->AddImmediate(ToNegatedConstant(node));
}
InstructionOperand UseLocation(Node* node, LinkageLocation location) {
return Use(node, ToUnallocatedOperand(location, GetVReg(node)));
}
......@@ -225,6 +229,19 @@ class OperandGenerator {
return Constant(static_cast<int32_t>(0));
}
static Constant ToNegatedConstant(const Node* node) {
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
return Constant(-OpParameter<int32_t>(node));
case IrOpcode::kInt64Constant:
return Constant(-OpParameter<int64_t>(node));
default:
break;
}
UNREACHABLE();
return Constant(static_cast<int32_t>(0));
}
UnallocatedOperand Define(Node* node, UnallocatedOperand operand) {
DCHECK_NOT_NULL(node);
DCHECK_EQ(operand.virtual_register(), GetVReg(node));
......
......@@ -318,11 +318,12 @@ typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
IrOpcode::kWord64Shl> Int64ScaleMatcher;
template <class BinopMatcher, IrOpcode::Value kAddOpcode,
IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode>
template <class BinopMatcher, IrOpcode::Value AddOpcode,
IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
IrOpcode::Value kShiftOpcode>
struct AddMatcher : public BinopMatcher {
static const IrOpcode::Value kOpcode = kAddOpcode;
static const IrOpcode::Value kAddOpcode = AddOpcode;
static const IrOpcode::Value kSubOpcode = SubOpcode;
typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher;
AddMatcher(Node* node, bool allow_input_swap)
......@@ -373,6 +374,9 @@ struct AddMatcher : public BinopMatcher {
if (this->right().opcode() == kAddOpcode &&
this->left().opcode() != kAddOpcode) {
this->SwapInputs();
} else if (this->right().opcode() == kSubOpcode &&
this->left().opcode() != kSubOpcode) {
this->SwapInputs();
}
}
......@@ -380,11 +384,14 @@ struct AddMatcher : public BinopMatcher {
bool power_of_two_plus_one_;
};
typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul,
IrOpcode::kWord32Shl> Int32AddMatcher;
typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Mul,
IrOpcode::kWord64Shl> Int64AddMatcher;
typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>
Int32AddMatcher;
typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>
Int64AddMatcher;
enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
template <class AddMatcher>
struct BaseWithIndexAndDisplacementMatcher {
......@@ -393,7 +400,8 @@ struct BaseWithIndexAndDisplacementMatcher {
index_(nullptr),
scale_(0),
base_(nullptr),
displacement_(nullptr) {
displacement_(nullptr),
displacement_mode_(kPositiveDisplacement) {
Initialize(node, allow_input_swap);
}
......@@ -402,7 +410,8 @@ struct BaseWithIndexAndDisplacementMatcher {
index_(nullptr),
scale_(0),
base_(nullptr),
displacement_(nullptr) {
displacement_(nullptr),
displacement_mode_(kPositiveDisplacement) {
Initialize(node, node->op()->HasProperty(Operator::kCommutative));
}
......@@ -411,6 +420,7 @@ struct BaseWithIndexAndDisplacementMatcher {
int scale() const { return scale_; }
Node* base() const { return base_; }
Node* displacement() const { return displacement_; }
DisplacementMode displacement_mode() const { return displacement_mode_; }
private:
bool matches_;
......@@ -418,6 +428,7 @@ struct BaseWithIndexAndDisplacementMatcher {
int scale_;
Node* base_;
Node* displacement_;
DisplacementMode displacement_mode_;
void Initialize(Node* node, bool allow_input_swap) {
// The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
......@@ -445,13 +456,26 @@ struct BaseWithIndexAndDisplacementMatcher {
Node* index = nullptr;
Node* scale_expression = nullptr;
bool power_of_two_plus_one = false;
DisplacementMode displacement_mode = kPositiveDisplacement;
int scale = 0;
if (m.HasIndexInput() && left->OwnedBy(node)) {
index = m.IndexInput();
scale = m.scale();
scale_expression = left;
power_of_two_plus_one = m.power_of_two_plus_one();
if (right->opcode() == AddMatcher::kOpcode && right->OwnedBy(node)) {
bool match_found = false;
if (right->opcode() == AddMatcher::kSubOpcode && right->OwnedBy(node)) {
AddMatcher right_matcher(right);
if (right_matcher.right().HasValue()) {
// (S + (B - D))
base = right_matcher.left().node();
displacement = right_matcher.right().node();
displacement_mode = kNegativeDisplacement;
match_found = true;
}
}
if (!match_found) {
if (right->opcode() == AddMatcher::kAddOpcode && right->OwnedBy(node)) {
AddMatcher right_matcher(right);
if (right_matcher.right().HasValue()) {
// (S + (B + D))
......@@ -468,8 +492,35 @@ struct BaseWithIndexAndDisplacementMatcher {
// (S + B)
base = right;
}
}
} else {
if (left->opcode() == AddMatcher::kOpcode && left->OwnedBy(node)) {
bool match_found = false;
if (left->opcode() == AddMatcher::kSubOpcode && left->OwnedBy(node)) {
AddMatcher left_matcher(left);
Node* left_left = left_matcher.left().node();
Node* left_right = left_matcher.right().node();
if (left_matcher.right().HasValue()) {
if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
// ((S - D) + B)
index = left_matcher.IndexInput();
scale = left_matcher.scale();
scale_expression = left_left;
power_of_two_plus_one = left_matcher.power_of_two_plus_one();
displacement = left_right;
displacement_mode = kNegativeDisplacement;
base = right;
} else {
// ((B - D) + B)
index = left_left;
displacement = left_right;
displacement_mode = kNegativeDisplacement;
base = right;
}
match_found = true;
}
}
if (!match_found) {
if (left->opcode() == AddMatcher::kAddOpcode && left->OwnedBy(node)) {
AddMatcher left_matcher(left);
Node* left_left = left_matcher.left().node();
Node* left_right = left_matcher.right().node();
......@@ -524,6 +575,7 @@ struct BaseWithIndexAndDisplacementMatcher {
}
}
}
}
int64_t value = 0;
if (displacement != nullptr) {
switch (displacement->opcode()) {
......@@ -557,6 +609,7 @@ struct BaseWithIndexAndDisplacementMatcher {
}
base_ = base;
displacement_ = displacement;
displacement_mode_ = displacement_mode;
index_ = index;
scale_ = scale;
matches_ = true;
......
......@@ -70,6 +70,7 @@ class X64OperandGenerator final : public OperandGenerator {
AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent,
Node* base, Node* displacement,
DisplacementMode displacement_mode,
InstructionOperand inputs[],
size_t* input_count) {
AddressingMode mode = kMode_MRI;
......@@ -79,7 +80,9 @@ class X64OperandGenerator final : public OperandGenerator {
DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
inputs[(*input_count)++] = UseRegister(index);
if (displacement != nullptr) {
inputs[(*input_count)++] = UseImmediate(displacement);
inputs[(*input_count)++] = displacement_mode
? UseNegatedImmediate(displacement)
: UseImmediate(displacement);
static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
kMode_MR4I, kMode_MR8I};
mode = kMRnI_modes[scale_exponent];
......@@ -92,7 +95,9 @@ class X64OperandGenerator final : public OperandGenerator {
if (displacement == nullptr) {
mode = kMode_MR;
} else {
inputs[(*input_count)++] = UseImmediate(displacement);
inputs[(*input_count)++] = displacement_mode == kNegativeDisplacement
? UseNegatedImmediate(displacement)
: UseImmediate(displacement);
mode = kMode_MRI;
}
}
......@@ -101,7 +106,9 @@ class X64OperandGenerator final : public OperandGenerator {
DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
inputs[(*input_count)++] = UseRegister(index);
if (displacement != nullptr) {
inputs[(*input_count)++] = UseImmediate(displacement);
inputs[(*input_count)++] = displacement_mode == kNegativeDisplacement
? UseNegatedImmediate(displacement)
: UseImmediate(displacement);
static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
kMode_M4I, kMode_M8I};
mode = kMnI_modes[scale_exponent];
......@@ -124,8 +131,9 @@ class X64OperandGenerator final : public OperandGenerator {
BaseWithIndexAndDisplacement64Matcher m(operand, true);
DCHECK(m.matches());
if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
m.displacement(), inputs, input_count);
return GenerateMemoryOperandInputs(
m.index(), m.scale(), m.base(), m.displacement(),
m.displacement_mode(), inputs, input_count);
} else {
inputs[(*input_count)++] = UseRegister(operand->InputAt(0));
inputs[(*input_count)++] = UseRegister(operand->InputAt(1));
......@@ -542,16 +550,16 @@ void VisitWord64Shift(InstructionSelector* selector, Node* node,
}
}
void EmitLea(InstructionSelector* selector, InstructionCode opcode,
Node* result, Node* index, int scale, Node* base,
Node* displacement) {
Node* displacement, DisplacementMode displacement_mode) {
X64OperandGenerator g(selector);
InstructionOperand inputs[4];
size_t input_count = 0;
AddressingMode mode = g.GenerateMemoryOperandInputs(
index, scale, base, displacement, inputs, &input_count);
AddressingMode mode =
g.GenerateMemoryOperandInputs(index, scale, base, displacement,
displacement_mode, inputs, &input_count);
DCHECK_NE(0u, input_count);
DCHECK_GE(arraysize(inputs), input_count);
......@@ -572,7 +580,8 @@ void InstructionSelector::VisitWord32Shl(Node* node) {
if (m.matches()) {
Node* index = node->InputAt(0);
Node* base = m.power_of_two_plus_one() ? index : nullptr;
EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr);
EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr,
kPositiveDisplacement);
return;
}
VisitWord32Shift(this, node, kX64Shl32);
......@@ -756,7 +765,7 @@ void InstructionSelector::VisitInt32Add(Node* node) {
if (m.matches() &&
(m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
EmitLea(this, kX64Lea32, node, m.index(), m.scale(), m.base(),
m.displacement());
m.displacement(), m.displacement_mode());
return;
}
......@@ -881,7 +890,8 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
if (m.matches()) {
Node* index = node->InputAt(0);
Node* base = m.power_of_two_plus_one() ? index : nullptr;
EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr);
EmitLea(this, kX64Lea32, node, index, m.scale(), base, nullptr,
kPositiveDisplacement);
return;
}
VisitMul(this, node, kX64Imul32);
......
......@@ -30,13 +30,15 @@ class NodeMatcherTest : public GraphTest {
namespace {
template <class Matcher>
void CheckBaseWithIndexAndDisplacement(Matcher* matcher, Node* index, int scale,
Node* base, Node* displacement) {
void CheckBaseWithIndexAndDisplacement(
Matcher* matcher, Node* index, int scale, Node* base, Node* displacement,
DisplacementMode displacement_mode = kPositiveDisplacement) {
EXPECT_TRUE(matcher->matches());
EXPECT_EQ(index, matcher->index());
EXPECT_EQ(scale, matcher->scale());
EXPECT_EQ(base, matcher->base());
EXPECT_EQ(displacement, matcher->displacement());
EXPECT_EQ(displacement_mode, matcher->displacement_mode());
}
} // namespace
......@@ -90,6 +92,9 @@ TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
const Operator* a_op = machine()->Int32Add();
USE(a_op);
const Operator* sub_op = machine()->Int32Sub();
USE(sub_op);
const Operator* m_op = machine()->Int32Mul();
Node* m1 = graph()->NewNode(m_op, p1, d1);
Node* m2 = graph()->NewNode(m_op, p1, d2);
......@@ -354,7 +359,25 @@ TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
// Check that scales that require using the base address work dorrectly.
// S3 + (B0 - D15) -> [p1, 2, b0, d15, true]
s3 = graph()->NewNode(s_op, p1, d3);
BaseWithIndexAndDisplacement32Matcher match44(
graph()->NewNode(a_op, s3, graph()->NewNode(sub_op, b0, d15)));
CheckBaseWithIndexAndDisplacement(&match44, p1, 3, b0, d15,
kNegativeDisplacement);
// B0 + (B1 - D15) -> [p1, 2, b0, d15, true]
BaseWithIndexAndDisplacement32Matcher match45(
graph()->NewNode(a_op, b0, graph()->NewNode(sub_op, b1, d15)));
CheckBaseWithIndexAndDisplacement(&match45, b1, 0, b0, d15,
kNegativeDisplacement);
// (B0 - D15) + S3 -> [p1, 2, b0, d15, true]
s3 = graph()->NewNode(s_op, p1, d3);
BaseWithIndexAndDisplacement32Matcher match46(
graph()->NewNode(a_op, graph()->NewNode(sub_op, b0, d15), s3));
CheckBaseWithIndexAndDisplacement(&match46, p1, 3, b0, d15,
kNegativeDisplacement);
}
......@@ -409,6 +432,9 @@ TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
const Operator* a_op = machine()->Int64Add();
USE(a_op);
const Operator* sub_op = machine()->Int64Sub();
USE(sub_op);
const Operator* m_op = machine()->Int64Mul();
Node* m1 = graph()->NewNode(m_op, p1, d1);
Node* m2 = graph()->NewNode(m_op, p1, d2);
......@@ -726,8 +752,27 @@ TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
BaseWithIndexAndDisplacement64Matcher match50(
graph()->NewNode(a_op, m3, temp));
CheckBaseWithIndexAndDisplacement(&match50, m3, 0, b0, d15);
}
// S3 + (B0 - D15) -> [p1, 2, b0, d15, true]
s3 = graph()->NewNode(s_op, p1, d3);
BaseWithIndexAndDisplacement64Matcher match51(
graph()->NewNode(a_op, s3, graph()->NewNode(sub_op, b0, d15)));
CheckBaseWithIndexAndDisplacement(&match51, p1, 3, b0, d15,
kNegativeDisplacement);
// B0 + (B1 - D15) -> [p1, 2, b0, d15, true]
BaseWithIndexAndDisplacement64Matcher match52(
graph()->NewNode(a_op, b0, graph()->NewNode(sub_op, b1, d15)));
CheckBaseWithIndexAndDisplacement(&match52, b1, 0, b0, d15,
kNegativeDisplacement);
// (B0 - D15) + S3 -> [p1, 2, b0, d15, true]
s3 = graph()->NewNode(s_op, p1, d3);
BaseWithIndexAndDisplacement64Matcher match53(
graph()->NewNode(a_op, graph()->NewNode(sub_op, b0, d15), s3));
CheckBaseWithIndexAndDisplacement(&match53, p1, 3, b0, d15,
kNegativeDisplacement);
}
TEST_F(NodeMatcherTest, BranchMatcher_match) {
Node* zero = graph()->NewNode(common()->Int32Constant(0));
......
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