// case that there are only two operands to the add and one of them isn't
// live, use a plain "addl".
if (m.matches() && (m.constant() == NULL || g.CanBeImmediate(m.constant()))) {
- if (m.offset() != NULL) {
- if (m.constant() == NULL) {
- if (m.scaled() != NULL && m.scale_exponent() == 0) {
- if (!IsLive(m.offset())) {
- Emit(kX64Add32, g.DefineSameAsFirst(node),
- g.UseRegister(m.offset()), g.Use(m.scaled()));
- return;
- } else if (!IsLive(m.scaled())) {
- Emit(kX64Add32, g.DefineSameAsFirst(node),
- g.UseRegister(m.scaled()), g.Use(m.offset()));
- return;
- }
- }
- } else {
- if (m.scale_exponent() == 0) {
- if (m.scaled() == NULL || m.offset() == NULL) {
- Node* non_constant = m.scaled() == NULL ? m.offset() : m.scaled();
- if (!IsLive(non_constant)) {
- Emit(kX64Add32, g.DefineSameAsFirst(node),
- g.UseRegister(non_constant), g.UseImmediate(m.constant()));
- return;
- }
- }
- }
- }
- }
-
InstructionOperand* inputs[4];
size_t input_count = 0;
AddressingMode mode = GenerateMemoryOperandInputs(
Emit(kX64Neg32, g.DefineSameAsFirst(node), g.UseRegister(m.right().node()));
} else {
if (m.right().HasValue() && g.CanBeImmediate(m.right().node())) {
- if (IsLive(m.left().node())) {
- // 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;
- }
+ // Turn subtractions of constant values into immediate "leal" instructions
+ // by negating the value.
+ Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI),
+ g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+ g.TempImmediate(-m.right().Value()));
+ return;
}
VisitBinop(this, node, kX64Sub32);
}
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const c0 = m.Int32Constant(15);
- // If there is only a single use of an add's input, use an "addl" not a
- // "leal", it is faster.
+ // If one of the add's operands is only used once, use an "leal", even though
+ // an "addl" could be used. The "leal" has proven faster--out best guess is
+ // that it gives the register allocation more freedom and it doesn't set
+ // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+ // register allocation, then code generation will select an "addl" later for
+ // the cases that have been measured to be faster.
Node* const v0 = m.Int32Add(p0, c0);
m.Return(v0);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64Add32, s[0]->arch_opcode());
- EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+ EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+ EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
Node* const p0 = m.Parameter(0);
Node* const c0 = m.Int32Constant(1);
// If there is only a single use of an add's input and the immediate constant
- // for the add is 1, use inc.
+ // for the add is 1, don't use an inc. It is much slower on modern Intel
+ // architectures.
m.Return(m.Int32Add(p0, c0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64Add32, s[0]->arch_opcode());
- EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+ EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+ EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const c0 = m.Int32Constant(15);
- // If there is only a single use of an add's input, use "addl"
+ // If one of the add's operands is only used once, use an "leal", even though
+ // an "addl" could be used. The "leal" has proven faster--out best guess is
+ // that it gives the register allocation more freedom and it doesn't set
+ // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+ // register allocation, then code generation will select an "addl" later for
+ // the cases that have been measured to be faster.
m.Return(m.Int32Add(c0, p0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64Add32, s[0]->arch_opcode());
- EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+ EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+ EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
- // If one of the add's operands is only used once, use an "addl".
+ // If one of the add's operands is only used once, use an "leal", even though
+ // an "addl" could be used. The "leal" has proven faster--out best guess is
+ // that it gives the register allocation more freedom and it doesn't set
+ // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+ // register allocation, then code generation will select an "addl" later for
+ // the cases that have been measured to be faster.
m.Return(m.Int32Add(p0, p1));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64Add32, s[0]->arch_opcode());
- EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+ EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+ EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
m.Return(m.Int32Sub(p0, c0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64Sub32, s[0]->arch_opcode());
- EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+ EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+ EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
ASSERT_EQ(2U, s[1]->InputCount());
- EXPECT_EQ(kX64Add32, s[1]->arch_opcode());
+ EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(1)));
EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));