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