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); |
} |
} |