Index: src/compiler/arm/instruction-selector-arm.cc |
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc |
index a071bbccf8422ff371018a68085d46fea377505d..2bae1409c5e3bae8ef5d61aff0b068a6dc11be70 100644 |
--- a/src/compiler/arm/instruction-selector-arm.cc |
+++ b/src/compiler/arm/instruction-selector-arm.cc |
@@ -91,6 +91,14 @@ class ArmOperandGenerator : public OperandGenerator { |
case kArmUdiv: |
case kArmBfc: |
case kArmUbfx: |
+ case kArmSxtb: |
+ case kArmSxth: |
+ case kArmSxtab: |
+ case kArmSxtah: |
+ case kArmUxtb: |
+ case kArmUxth: |
+ case kArmUxtab: |
+ case kArmUxtah: |
case kArmVcmpF64: |
case kArmVaddF64: |
case kArmVsubF64: |
@@ -255,8 +263,20 @@ static void VisitBinop(InstructionSelector* selector, Node* node, |
InstructionOperand* outputs[2]; |
size_t output_count = 0; |
- if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
- &input_count, &inputs[1])) { |
+ if (m.left().node() == m.right().node()) { |
+ // If both inputs refer to the same operand, enforce allocating a register |
+ // for both of them to ensure that we don't end up generating code like |
+ // this: |
+ // |
+ // mov r0, r1, asr #16 |
+ // adds r0, r0, r1, asr #16 |
+ // bvs label |
+ InstructionOperand* const input = g.UseRegister(m.left().node()); |
+ opcode |= AddressingModeField::encode(kMode_Operand2_R); |
+ inputs[input_count++] = input; |
+ inputs[input_count++] = input; |
+ } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
+ &input_count, &inputs[1])) { |
inputs[0] = g.UseRegister(m.left().node()); |
input_count++; |
} else if (TryMatchImmediateOrShift(selector, &reverse_opcode, |
@@ -430,12 +450,12 @@ void InstructionSelector::VisitWord32And(Node* node) { |
return; |
} |
} |
- if (IsSupported(ARMv7) && m.right().HasValue()) { |
- // Try to interpret this AND as UBFX. |
+ if (m.right().HasValue()) { |
uint32_t const value = m.right().Value(); |
uint32_t width = base::bits::CountPopulation32(value); |
uint32_t msb = base::bits::CountLeadingZeros32(value); |
- if (width != 0 && msb + width == 32) { |
+ // Try to interpret this AND as UBFX. |
+ if (IsSupported(ARMv7) && width != 0 && msb + width == 32) { |
DCHECK_EQ(0, base::bits::CountTrailingZeros32(value)); |
if (m.left().IsWord32Shr()) { |
Int32BinopMatcher mleft(m.left().node()); |
@@ -450,7 +470,6 @@ void InstructionSelector::VisitWord32And(Node* node) { |
g.TempImmediate(0), g.TempImmediate(width)); |
return; |
} |
- |
// Try to interpret this AND as BIC. |
if (g.CanBeImmediate(~value)) { |
Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I), |
@@ -458,16 +477,23 @@ void InstructionSelector::VisitWord32And(Node* node) { |
g.TempImmediate(~value)); |
return; |
} |
- |
- // Try to interpret this AND as BFC. |
- width = 32 - width; |
- msb = base::bits::CountLeadingZeros32(~value); |
- uint32_t lsb = base::bits::CountTrailingZeros32(~value); |
- if (msb + width + lsb == 32) { |
- Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), |
- g.TempImmediate(lsb), g.TempImmediate(width)); |
+ // Try to interpret this AND as UXTH. |
+ if (value == 0xffff) { |
+ Emit(kArmUxth, g.DefineAsRegister(m.node()), |
+ g.UseRegister(m.left().node()), g.TempImmediate(0)); |
return; |
} |
+ // Try to interpret this AND as BFC. |
+ if (IsSupported(ARMv7)) { |
+ width = 32 - width; |
+ msb = base::bits::CountLeadingZeros32(~value); |
+ uint32_t lsb = base::bits::CountTrailingZeros32(~value); |
+ if (msb + width + lsb == 32) { |
+ Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), |
+ g.TempImmediate(lsb), g.TempImmediate(width)); |
+ return; |
+ } |
+ } |
} |
VisitBinop(this, node, kArmAnd, kArmAnd); |
} |
@@ -571,6 +597,20 @@ void InstructionSelector::VisitWord32Shr(Node* node) { |
void InstructionSelector::VisitWord32Sar(Node* node) { |
+ ArmOperandGenerator g(this); |
+ Int32BinopMatcher m(node); |
+ if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) { |
+ Int32BinopMatcher mleft(m.left().node()); |
+ if (mleft.right().Is(16) && m.right().Is(16)) { |
+ Emit(kArmSxth, g.DefineAsRegister(node), |
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } else if (mleft.right().Is(24) && m.right().Is(24)) { |
+ Emit(kArmSxtb, g.DefineAsRegister(node), |
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } |
+ } |
VisitShift(this, node, TryMatchASR); |
} |
@@ -583,31 +623,113 @@ void InstructionSelector::VisitWord32Ror(Node* node) { |
void InstructionSelector::VisitInt32Add(Node* node) { |
ArmOperandGenerator g(this); |
Int32BinopMatcher m(node); |
- if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) { |
- Int32BinopMatcher mleft(m.left().node()); |
- Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()), |
- g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); |
- return; |
- } |
- if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) { |
- Int32BinopMatcher mright(m.right().node()); |
- Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), |
- g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); |
- return; |
- } |
- if (m.left().IsInt32MulHigh() && CanCover(node, m.left().node())) { |
- Int32BinopMatcher mleft(m.left().node()); |
- Emit(kArmSmmla, g.DefineAsRegister(node), |
- g.UseRegister(mleft.left().node()), |
- g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); |
- return; |
+ if (CanCover(node, m.left().node())) { |
+ switch (m.left().opcode()) { |
+ case IrOpcode::kInt32Mul: { |
+ Int32BinopMatcher mleft(m.left().node()); |
+ Emit(kArmMla, g.DefineAsRegister(node), |
+ g.UseRegister(mleft.left().node()), |
+ g.UseRegister(mleft.right().node()), |
+ g.UseRegister(m.right().node())); |
+ return; |
+ } |
+ case IrOpcode::kInt32MulHigh: { |
+ Int32BinopMatcher mleft(m.left().node()); |
+ Emit(kArmSmmla, g.DefineAsRegister(node), |
+ g.UseRegister(mleft.left().node()), |
+ g.UseRegister(mleft.right().node()), |
+ g.UseRegister(m.right().node())); |
+ return; |
+ } |
+ case IrOpcode::kWord32And: { |
+ Int32BinopMatcher mleft(m.left().node()); |
+ if (mleft.right().Is(0xff)) { |
+ Emit(kArmUxtab, g.DefineAsRegister(node), |
+ g.UseRegister(m.right().node()), |
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } else if (mleft.right().Is(0xffff)) { |
+ Emit(kArmUxtah, g.DefineAsRegister(node), |
+ g.UseRegister(m.right().node()), |
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } |
+ } |
+ case IrOpcode::kWord32Sar: { |
+ Int32BinopMatcher mleft(m.left().node()); |
+ if (CanCover(mleft.node(), mleft.left().node()) && |
+ mleft.left().IsWord32Shl()) { |
+ Int32BinopMatcher mleftleft(mleft.left().node()); |
+ if (mleft.right().Is(24) && mleftleft.right().Is(24)) { |
+ Emit(kArmSxtab, g.DefineAsRegister(node), |
+ g.UseRegister(m.right().node()), |
+ g.UseRegister(mleftleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) { |
+ Emit(kArmSxtah, g.DefineAsRegister(node), |
+ g.UseRegister(m.right().node()), |
+ g.UseRegister(mleftleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } |
+ } |
+ } |
+ default: |
+ break; |
+ } |
} |
- if (m.right().IsInt32MulHigh() && CanCover(node, m.right().node())) { |
- Int32BinopMatcher mright(m.right().node()); |
- Emit(kArmSmmla, g.DefineAsRegister(node), |
- g.UseRegister(mright.left().node()), |
- g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); |
- return; |
+ if (CanCover(node, m.right().node())) { |
+ switch (m.right().opcode()) { |
+ case IrOpcode::kInt32Mul: { |
+ Int32BinopMatcher mright(m.right().node()); |
+ Emit(kArmMla, g.DefineAsRegister(node), |
+ g.UseRegister(mright.left().node()), |
+ g.UseRegister(mright.right().node()), |
+ g.UseRegister(m.left().node())); |
+ return; |
+ } |
+ case IrOpcode::kInt32MulHigh: { |
+ Int32BinopMatcher mright(m.right().node()); |
+ Emit(kArmSmmla, g.DefineAsRegister(node), |
+ g.UseRegister(mright.left().node()), |
+ g.UseRegister(mright.right().node()), |
+ g.UseRegister(m.left().node())); |
+ return; |
+ } |
+ case IrOpcode::kWord32And: { |
+ Int32BinopMatcher mright(m.right().node()); |
+ if (mright.right().Is(0xff)) { |
+ Emit(kArmUxtab, g.DefineAsRegister(node), |
+ g.UseRegister(m.left().node()), |
+ g.UseRegister(mright.left().node()), g.TempImmediate(0)); |
+ return; |
+ } else if (mright.right().Is(0xffff)) { |
+ Emit(kArmUxtah, g.DefineAsRegister(node), |
+ g.UseRegister(m.left().node()), |
+ g.UseRegister(mright.left().node()), g.TempImmediate(0)); |
+ return; |
+ } |
+ } |
+ case IrOpcode::kWord32Sar: { |
+ Int32BinopMatcher mright(m.right().node()); |
+ if (CanCover(mright.node(), mright.left().node()) && |
+ mright.left().IsWord32Shl()) { |
+ Int32BinopMatcher mrightleft(mright.left().node()); |
+ if (mright.right().Is(24) && mrightleft.right().Is(24)) { |
+ Emit(kArmSxtab, g.DefineAsRegister(node), |
+ g.UseRegister(m.left().node()), |
+ g.UseRegister(mrightleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } else if (mright.right().Is(16) && mrightleft.right().Is(16)) { |
+ Emit(kArmSxtah, g.DefineAsRegister(node), |
+ g.UseRegister(m.left().node()), |
+ g.UseRegister(mrightleft.left().node()), g.TempImmediate(0)); |
+ return; |
+ } |
+ } |
+ } |
+ default: |
+ break; |
+ } |
} |
VisitBinop(this, node, kArmAdd, kArmAdd); |
} |