| Index: src/compiler/x64/instruction-selector-x64.cc
|
| diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc
|
| index ce7ce56616522b995dc51ce5ce3a1091556ad33c..9547a635090f8bd8c9418846c1a62eebb9d2b47b 100644
|
| --- a/src/compiler/x64/instruction-selector-x64.cc
|
| +++ b/src/compiler/x64/instruction-selector-x64.cc
|
| @@ -434,9 +434,33 @@ void InstructionSelector::VisitInt32Add(Node* node) {
|
| ScaledWithOffset32Matcher m(node);
|
| X64OperandGenerator g(this);
|
| if (m.matches() && (m.constant() == NULL || g.CanBeImmediate(m.constant()))) {
|
| + // The add can be represented as a "leal", but there may be a smaller
|
| + // representation that is better and no more expensive.
|
| + if (m.offset() != NULL) {
|
| + if (m.scaled() == NULL) {
|
| + if (!IsLive(m.offset())) {
|
| + // If the add is of the form (r1 + immediate) and the non-constant
|
| + // input to the add is owned by the add, then it doesn't need to be
|
| + // preserved across the operation, so use more compact,
|
| + // source-register-overwriting versions when they are available and
|
| + // smaller, e.g. "incl" and "decl".
|
| + int32_t value =
|
| + m.constant() == NULL ? 0 : OpParameter<int32_t>(m.constant());
|
| + if (value == 1) {
|
| + Emit(kX64Inc32, g.DefineSameAsFirst(node),
|
| + g.UseRegister(m.offset()));
|
| + return;
|
| + } else if (value == -1) {
|
| + Emit(kX64Dec32, g.DefineSameAsFirst(node),
|
| + g.UseRegister(m.offset()));
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| InstructionOperand* inputs[4];
|
| size_t input_count = 0;
|
| -
|
| AddressingMode mode = GenerateMemoryOperandInputs(
|
| &g, m.scaled(), m.scale_exponent(), m.offset(), m.constant(), inputs,
|
| &input_count);
|
| @@ -468,6 +492,31 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
|
| if (m.left().Is(0)) {
|
| Emit(kX64Neg32, g.DefineSameAsFirst(node), g.UseRegister(m.right().node()));
|
| } else {
|
| + if (m.right().HasValue() && g.CanBeImmediate(m.right().node())) {
|
| + // If the Non-constant input is owned by the subtract, using a "decl" or
|
| + // "incl" that overwrites that input is smaller and probably an overall
|
| + // win.
|
| + if (!IsLive(m.left().node())) {
|
| + if (m.right().Value() == 1) {
|
| + Emit(kX64Dec32, g.DefineSameAsFirst(node),
|
| + g.UseRegister(m.left().node()));
|
| + return;
|
| + }
|
| + if (m.right().Value() == -1) {
|
| + Emit(kX64Inc32, g.DefineSameAsFirst(node),
|
| + g.UseRegister(m.left().node()));
|
| + return;
|
| + }
|
| + } else {
|
| + // Special handling for subtraction of constants where the non-constant
|
| + // input is used elsewhere. To eliminate the gap move before the sub to
|
| + // copy the destination register, use a "leal" instead.
|
| + Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI),
|
| + g.DefineAsRegister(node), g.UseRegister(m.left().node()),
|
| + g.TempImmediate(-m.right().Value()));
|
| + return;
|
| + }
|
| + }
|
| VisitBinop(this, node, kX64Sub32);
|
| }
|
| }
|
|
|