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 276b810ed20c11881c0e8cca220f5829e13b63c8..8ec4dedd218e8c642d6a0689071b529e40fe39e1 100644 |
--- a/src/compiler/arm/instruction-selector-arm.cc |
+++ b/src/compiler/arm/instruction-selector-arm.cc |
@@ -78,16 +78,14 @@ class ArmOperandGenerator : public OperandGenerator { |
namespace { |
-void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode, |
- Node* node) { |
+void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { |
ArmOperandGenerator g(selector); |
selector->Emit(opcode, g.DefineAsRegister(node), |
g.UseRegister(node->InputAt(0))); |
} |
-void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode, |
- Node* node) { |
+void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { |
ArmOperandGenerator g(selector); |
selector->Emit(opcode, g.DefineAsRegister(node), |
g.UseRegister(node->InputAt(0)), |
@@ -251,6 +249,56 @@ void VisitBinop(InstructionSelector* selector, Node* node, |
} |
+void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, |
+ ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, |
+ InstructionOperand result_operand, InstructionOperand left_operand, |
+ InstructionOperand right_operand) { |
+ ArmOperandGenerator g(selector); |
+ if (selector->IsSupported(SUDIV)) { |
+ selector->Emit(div_opcode, result_operand, left_operand, right_operand); |
+ return; |
+ } |
+ InstructionOperand left_double_operand = g.TempDoubleRegister(); |
+ InstructionOperand right_double_operand = g.TempDoubleRegister(); |
+ InstructionOperand result_double_operand = g.TempDoubleRegister(); |
+ selector->Emit(f64i32_opcode, left_double_operand, left_operand); |
+ selector->Emit(f64i32_opcode, right_double_operand, right_operand); |
+ selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, |
+ right_double_operand); |
+ selector->Emit(i32f64_opcode, result_operand, result_double_operand); |
+} |
+ |
+ |
+void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode, |
+ ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) { |
+ ArmOperandGenerator g(selector); |
+ Int32BinopMatcher m(node); |
+ EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, |
+ g.DefineAsRegister(node), g.UseRegister(m.left().node()), |
+ g.UseRegister(m.right().node())); |
+} |
+ |
+ |
+void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode, |
+ ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) { |
+ ArmOperandGenerator g(selector); |
+ Int32BinopMatcher m(node); |
+ InstructionOperand div_operand = g.TempRegister(); |
+ InstructionOperand result_operand = g.DefineAsRegister(node); |
+ InstructionOperand left_operand = g.UseRegister(m.left().node()); |
+ InstructionOperand right_operand = g.UseRegister(m.right().node()); |
+ EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, |
+ left_operand, right_operand); |
+ if (selector->IsSupported(MLS)) { |
+ selector->Emit(kArmMls, result_operand, div_operand, right_operand, |
+ left_operand); |
+ } else { |
+ InstructionOperand mul_operand = g.TempRegister(); |
+ selector->Emit(kArmMul, mul_operand, div_operand, right_operand); |
+ selector->Emit(kArmSub, result_operand, left_operand, mul_operand); |
+ } |
+} |
+ |
} // namespace |
@@ -644,8 +692,7 @@ void InstructionSelector::VisitWord32Ror(Node* node) { |
void InstructionSelector::VisitWord32Clz(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmClz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmClz, node); |
} |
@@ -798,15 +845,12 @@ void InstructionSelector::VisitInt32Mul(Node* node) { |
return; |
} |
} |
- Emit(kArmMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()), |
- g.UseRegister(m.right().node())); |
+ VisitRRR(this, kArmMul, node); |
} |
void InstructionSelector::VisitInt32MulHigh(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), |
- g.UseRegister(node->InputAt(1))); |
+ VisitRRR(this, kArmSmmul, node); |
} |
@@ -819,38 +863,6 @@ void InstructionSelector::VisitUint32MulHigh(Node* node) { |
} |
-static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, |
- ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, |
- InstructionOperand result_operand, |
- InstructionOperand left_operand, |
- InstructionOperand right_operand) { |
- ArmOperandGenerator g(selector); |
- if (selector->IsSupported(SUDIV)) { |
- selector->Emit(div_opcode, result_operand, left_operand, right_operand); |
- return; |
- } |
- InstructionOperand left_double_operand = g.TempDoubleRegister(); |
- InstructionOperand right_double_operand = g.TempDoubleRegister(); |
- InstructionOperand result_double_operand = g.TempDoubleRegister(); |
- selector->Emit(f64i32_opcode, left_double_operand, left_operand); |
- selector->Emit(f64i32_opcode, right_double_operand, right_operand); |
- selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, |
- right_double_operand); |
- selector->Emit(i32f64_opcode, result_operand, result_double_operand); |
-} |
- |
- |
-static void VisitDiv(InstructionSelector* selector, Node* node, |
- ArchOpcode div_opcode, ArchOpcode f64i32_opcode, |
- ArchOpcode i32f64_opcode) { |
- ArmOperandGenerator g(selector); |
- Int32BinopMatcher m(node); |
- EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, |
- g.DefineAsRegister(node), g.UseRegister(m.left().node()), |
- g.UseRegister(m.right().node())); |
-} |
- |
- |
void InstructionSelector::VisitInt32Div(Node* node) { |
VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); |
} |
@@ -861,28 +873,6 @@ void InstructionSelector::VisitUint32Div(Node* node) { |
} |
-static void VisitMod(InstructionSelector* selector, Node* node, |
- ArchOpcode div_opcode, ArchOpcode f64i32_opcode, |
- ArchOpcode i32f64_opcode) { |
- ArmOperandGenerator g(selector); |
- Int32BinopMatcher m(node); |
- InstructionOperand div_operand = g.TempRegister(); |
- InstructionOperand result_operand = g.DefineAsRegister(node); |
- InstructionOperand left_operand = g.UseRegister(m.left().node()); |
- InstructionOperand right_operand = g.UseRegister(m.right().node()); |
- EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, |
- left_operand, right_operand); |
- if (selector->IsSupported(MLS)) { |
- selector->Emit(kArmMls, result_operand, div_operand, right_operand, |
- left_operand); |
- return; |
- } |
- InstructionOperand mul_operand = g.TempRegister(); |
- selector->Emit(kArmMul, mul_operand, div_operand, right_operand); |
- selector->Emit(kArmSub, result_operand, left_operand, mul_operand); |
-} |
- |
- |
void InstructionSelector::VisitInt32Mod(Node* node) { |
VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); |
} |
@@ -894,44 +884,53 @@ void InstructionSelector::VisitUint32Mod(Node* node) { |
void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVcvtF64F32, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVcvtF64F32, node); |
} |
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVcvtF64S32, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVcvtF64S32, node); |
} |
void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVcvtF64U32, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVcvtF64U32, node); |
} |
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVcvtS32F64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVcvtS32F64, node); |
} |
void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVcvtU32F64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVcvtU32F64, node); |
} |
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { |
+ VisitRR(this, kArmVcvtF32F64, node); |
+} |
+ |
+ |
+void InstructionSelector::VisitFloat32Add(Node* node) { |
ArmOperandGenerator g(this); |
- Emit(kArmVcvtF32F64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ Float32BinopMatcher m(node); |
+ if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) { |
+ Float32BinopMatcher mleft(m.left().node()); |
+ Emit(kArmVmlaF32, g.DefineSameAsFirst(node), |
+ g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()), |
+ g.UseRegister(mleft.right().node())); |
+ return; |
+ } |
+ if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) { |
+ Float32BinopMatcher mright(m.right().node()); |
+ Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), |
+ g.UseRegister(mright.left().node()), |
+ g.UseRegister(mright.right().node())); |
+ return; |
+ } |
+ VisitRRR(this, kArmVaddF32, node); |
} |
@@ -952,7 +951,26 @@ void InstructionSelector::VisitFloat64Add(Node* node) { |
g.UseRegister(mright.right().node())); |
return; |
} |
- VisitRRRFloat64(this, kArmVaddF64, node); |
+ VisitRRR(this, kArmVaddF64, node); |
+} |
+ |
+ |
+void InstructionSelector::VisitFloat32Sub(Node* node) { |
+ ArmOperandGenerator g(this); |
+ Float32BinopMatcher m(node); |
+ if (m.left().IsMinusZero()) { |
+ Emit(kArmVnegF32, g.DefineAsRegister(node), |
+ g.UseRegister(m.right().node())); |
+ return; |
+ } |
+ if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) { |
+ Float32BinopMatcher mright(m.right().node()); |
+ Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), |
+ g.UseRegister(mright.left().node()), |
+ g.UseRegister(mright.right().node())); |
+ return; |
+ } |
+ VisitRRR(this, kArmVsubF32, node); |
} |
@@ -983,17 +1001,27 @@ void InstructionSelector::VisitFloat64Sub(Node* node) { |
g.UseRegister(mright.right().node())); |
return; |
} |
- VisitRRRFloat64(this, kArmVsubF64, node); |
+ VisitRRR(this, kArmVsubF64, node); |
+} |
+ |
+ |
+void InstructionSelector::VisitFloat32Mul(Node* node) { |
+ VisitRRR(this, kArmVmulF32, node); |
} |
void InstructionSelector::VisitFloat64Mul(Node* node) { |
- VisitRRRFloat64(this, kArmVmulF64, node); |
+ VisitRRR(this, kArmVmulF64, node); |
+} |
+ |
+ |
+void InstructionSelector::VisitFloat32Div(Node* node) { |
+ VisitRRR(this, kArmVdivF32, node); |
} |
void InstructionSelector::VisitFloat64Div(Node* node) { |
- VisitRRRFloat64(this, kArmVdivF64, node); |
+ VisitRRR(this, kArmVdivF64, node); |
} |
@@ -1004,30 +1032,40 @@ void InstructionSelector::VisitFloat64Mod(Node* node) { |
} |
+void InstructionSelector::VisitFloat32Max(Node* node) { UNREACHABLE(); } |
+ |
+ |
void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); } |
+void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); } |
+ |
+ |
void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); } |
+void InstructionSelector::VisitFloat32Sqrt(Node* node) { |
+ VisitRR(this, kArmVsqrtF32, node); |
+} |
+ |
+ |
void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVsqrtF64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVsqrtF64, node); |
} |
void InstructionSelector::VisitFloat64RoundDown(Node* node) { |
- VisitRRFloat64(this, kArmVrintmF64, node); |
+ VisitRR(this, kArmVrintmF64, node); |
} |
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { |
- VisitRRFloat64(this, kArmVrintzF64, node); |
+ VisitRR(this, kArmVrintzF64, node); |
} |
void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { |
- VisitRRFloat64(this, kArmVrintaF64, node); |
+ VisitRR(this, kArmVrintaF64, node); |
} |
@@ -1091,7 +1129,27 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { |
namespace { |
-// Shared routine for multiple float compare operations. |
+// Shared routine for multiple float32 compare operations. |
+void VisitFloat32Compare(InstructionSelector* selector, Node* node, |
+ FlagsContinuation* cont) { |
+ ArmOperandGenerator g(selector); |
+ Float32BinopMatcher m(node); |
+ InstructionOperand rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node()) |
+ : g.UseRegister(m.right().node()); |
+ if (cont->IsBranch()) { |
+ selector->Emit(cont->Encode(kArmVcmpF32), g.NoOutput(), |
+ g.UseRegister(m.left().node()), rhs, |
+ g.Label(cont->true_block()), g.Label(cont->false_block())); |
+ } else { |
+ DCHECK(cont->IsSet()); |
+ selector->Emit(cont->Encode(kArmVcmpF32), |
+ g.DefineAsRegister(cont->result()), |
+ g.UseRegister(m.left().node()), rhs); |
+ } |
+} |
+ |
+ |
+// Shared routine for multiple float64 compare operations. |
void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
FlagsContinuation* cont) { |
ArmOperandGenerator g(selector); |
@@ -1189,6 +1247,15 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
case IrOpcode::kUint32LessThanOrEqual: |
cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
return VisitWordCompare(selector, value, cont); |
+ case IrOpcode::kFloat32Equal: |
+ cont->OverwriteAndNegateIfEqual(kEqual); |
+ return VisitFloat32Compare(selector, value, cont); |
+ case IrOpcode::kFloat32LessThan: |
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); |
+ return VisitFloat32Compare(selector, value, cont); |
+ case IrOpcode::kFloat32LessThanOrEqual: |
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
+ return VisitFloat32Compare(selector, value, cont); |
case IrOpcode::kFloat64Equal: |
cont->OverwriteAndNegateIfEqual(kEqual); |
return VisitFloat64Compare(selector, value, cont); |
@@ -1353,6 +1420,24 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
} |
+void InstructionSelector::VisitFloat32Equal(Node* node) { |
+ FlagsContinuation cont(kEqual, node); |
+ VisitFloat32Compare(this, node, &cont); |
+} |
+ |
+ |
+void InstructionSelector::VisitFloat32LessThan(Node* node) { |
+ FlagsContinuation cont(kUnsignedLessThan, node); |
+ VisitFloat32Compare(this, node, &cont); |
+} |
+ |
+ |
+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { |
+ FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
+ VisitFloat32Compare(this, node, &cont); |
+} |
+ |
+ |
void InstructionSelector::VisitFloat64Equal(Node* node) { |
FlagsContinuation cont(kEqual, node); |
VisitFloat64Compare(this, node, &cont); |
@@ -1372,16 +1457,12 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVmovLowU32F64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVmovLowU32F64, node); |
} |
void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { |
- ArmOperandGenerator g(this); |
- Emit(kArmVmovHighU32F64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+ VisitRR(this, kArmVmovHighU32F64, node); |
} |