From b1dfa2aee15b4617032b927cd95d97f85c82dd6f Mon Sep 17 00:00:00 2001 From: Florian Schneider Date: Mon, 31 Oct 2016 20:21:19 +0100 Subject: [PATCH] VM: Enable branch merging of isnan, isinf. More general ComparisonInstr by introducing TemplateComparison. R=zra@google.com Review URL: https://codereview.chromium.org/2463593002 . --- runtime/vm/branch_optimizer.cc | 3 + runtime/vm/constants_dbc.h | 4 +- runtime/vm/intermediate_language.cc | 17 ++- runtime/vm/intermediate_language.h | 120 ++++++++++++++-------- runtime/vm/intermediate_language_arm.cc | 44 ++++++-- runtime/vm/intermediate_language_arm64.cc | 51 +++++++-- runtime/vm/intermediate_language_dbc.cc | 46 +++++++-- runtime/vm/intermediate_language_ia32.cc | 76 +++++++++----- runtime/vm/intermediate_language_mips.cc | 82 +++++++++++---- runtime/vm/intermediate_language_x64.cc | 65 ++++++++---- runtime/vm/simulator_dbc.cc | 16 +-- 11 files changed, 379 insertions(+), 145 deletions(-) diff --git a/runtime/vm/branch_optimizer.cc b/runtime/vm/branch_optimizer.cc index b34baf76024..4ad12c1a065 100644 --- a/runtime/vm/branch_optimizer.cc +++ b/runtime/vm/branch_optimizer.cc @@ -44,6 +44,9 @@ bool BranchSimplifier::Match(JoinEntryInstr* block) { BranchInstr* branch = block->last_instruction()->AsBranch(); ASSERT(branch != NULL); ComparisonInstr* comparison = branch->comparison(); + if (comparison->InputCount() != 2) { + return false; + } Value* left = comparison->left(); PhiInstr* phi = left->definition()->AsPhi(); Value* right = comparison->right(); diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h index e93bc0b00b7..1c0d1bed974 100644 --- a/runtime/vm/constants_dbc.h +++ b/runtime/vm/constants_dbc.h @@ -729,8 +729,8 @@ namespace dart { V(DCeil, A_D, reg, reg, ___) \ V(DoubleToFloat, A_D, reg, reg, ___) \ V(FloatToDouble, A_D, reg, reg, ___) \ - V(DoubleIsNaN, A_D, reg, reg, ___) \ - V(DoubleIsInfinite, A_D, reg, reg, ___) \ + V(DoubleIsNaN, A, reg, ___, ___) \ + V(DoubleIsInfinite, A, reg, ___, ___) \ V(StoreStaticTOS, D, lit, ___, ___) \ V(PushStatic, D, lit, ___, ___) \ V(InitStaticTOS, 0, ___, ___, ___) \ diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index f3af7360173..fec4664478a 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -3020,13 +3020,13 @@ StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, Value* left, Value* right, bool needs_number_check) - : ComparisonInstr(token_pos, - kind, - left, - right, - Thread::Current()->GetNextDeoptId()), + : TemplateComparison(token_pos, + kind, + Thread::Current()->GetNextDeoptId()), needs_number_check_(needs_number_check) { ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); + SetInputAt(0, left); + SetInputAt(1, right); } @@ -3422,6 +3422,13 @@ void Environment::DeepCopyToOuter(Zone* zone, Instruction* instr) const { } +ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, + Value* new_right) { + UNREACHABLE(); + return NULL; +} + + ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, Value* new_right) { return new EqualityCompareInstr(token_pos(), diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index 57b98b75071..57f302180ca 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -910,6 +910,9 @@ FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) } private: + friend class BranchInstr; // For RawSetInputAt. + friend class IfThenElseInstr; // For RawSetInputAt. + virtual void RawSetInputAt(intptr_t i, Value* value) = 0; enum { @@ -2354,10 +2357,10 @@ class IndirectGotoInstr : public TemplateInstruction<1, NoThrow> { }; -class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> { +class ComparisonInstr : public Definition { public: - Value* left() const { return inputs_[0]; } - Value* right() const { return inputs_[1]; } + Value* left() const { return InputAt(0); } + Value* right() const { return InputAt(1); } virtual TokenPosition token_pos() const { return token_pos_; } Token::Kind kind() const { return kind_; } @@ -2396,17 +2399,11 @@ class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> { protected: ComparisonInstr(TokenPosition token_pos, Token::Kind kind, - Value* left, - Value* right, intptr_t deopt_id = Thread::kNoDeoptId) - : TemplateDefinition(deopt_id), + : Definition(deopt_id), token_pos_(token_pos), kind_(kind), operation_cid_(kIllegalCid) { - SetInputAt(0, left); - if (right != NULL) { - SetInputAt(1, right); - } } private: @@ -2418,6 +2415,47 @@ class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> { }; +class PureComparison : public ComparisonInstr { + public: + virtual bool AllowsCSE() const { return true; } + virtual EffectSet Dependencies() const { return EffectSet::None(); } + + virtual EffectSet Effects() const { return EffectSet::None(); } + + protected: + PureComparison(TokenPosition token_pos, Token::Kind kind, intptr_t deopt_id) + : ComparisonInstr(token_pos, kind, deopt_id) { } +}; + + +template class CSETrait = NoCSE> +class TemplateComparison : public CSETrait< + ComparisonInstr, PureComparison>::Base { + public: + TemplateComparison(TokenPosition token_pos, + Token::Kind kind, + intptr_t deopt_id = Thread::kNoDeoptId) + : CSETrait::Base( + token_pos, kind, deopt_id), + inputs_() { } + + virtual intptr_t InputCount() const { return N; } + virtual Value* InputAt(intptr_t i) const { return inputs_[i]; } + + virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; } + + protected: + EmbeddedArray inputs_; + + private: + virtual void RawSetInputAt(intptr_t i, Value* value) { + inputs_[i] = value; + } +}; + + class BranchInstr : public Instruction { public: explicit BranchInstr(ComparisonInstr* comparison) @@ -2976,7 +3014,7 @@ class PolymorphicInstanceCallInstr : public TemplateDefinition<0, Throws> { }; -class StrictCompareInstr : public ComparisonInstr { +class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> { public: StrictCompareInstr(TokenPosition token_pos, Token::Kind kind, @@ -3018,14 +3056,16 @@ class StrictCompareInstr : public ComparisonInstr { // Comparison instruction that is equivalent to the (left & right) == 0 // comparison pattern. -class TestSmiInstr : public ComparisonInstr { +class TestSmiInstr : public TemplateComparison<2, NoThrow, Pure> { public: TestSmiInstr(TokenPosition token_pos, Token::Kind kind, Value* left, Value* right) - : ComparisonInstr(token_pos, kind, left, right) { + : TemplateComparison(token_pos, kind) { ASSERT(kind == Token::kEQ || kind == Token::kNE); + SetInputAt(0, left); + SetInputAt(1, right); } DECLARE_INSTRUCTION(TestSmi); @@ -3053,24 +3093,21 @@ class TestSmiInstr : public ComparisonInstr { // Checks the input value cid against cids stored in a table and returns either // a result or deoptimizes. -// TODO(srdjan): Modify ComparisonInstr to allow 1 or 2 arguments, since -// TestCidInstr needs only one argument -class TestCidsInstr : public ComparisonInstr { +class TestCidsInstr : public TemplateComparison<1, NoThrow, Pure> { public: TestCidsInstr(TokenPosition token_pos, Token::Kind kind, Value* value, const ZoneGrowableArray& cid_results, intptr_t deopt_id) - : ComparisonInstr(token_pos, kind, value, NULL, deopt_id), + : TemplateComparison(token_pos, kind, deopt_id), cid_results_(cid_results), licm_hoisted_(false) { ASSERT((kind == Token::kIS) || (kind == Token::kISNOT)); + SetInputAt(0, value); set_operation_cid(kObjectCid); } - virtual intptr_t InputCount() const { return 1; } - const ZoneGrowableArray& cid_results() const { return cid_results_; } @@ -3110,7 +3147,7 @@ class TestCidsInstr : public ComparisonInstr { }; -class EqualityCompareInstr : public ComparisonInstr { +class EqualityCompareInstr : public TemplateComparison<2, NoThrow, Pure> { public: EqualityCompareInstr(TokenPosition token_pos, Token::Kind kind, @@ -3118,8 +3155,10 @@ class EqualityCompareInstr : public ComparisonInstr { Value* right, intptr_t cid, intptr_t deopt_id) - : ComparisonInstr(token_pos, kind, left, right, deopt_id) { + : TemplateComparison(token_pos, kind, deopt_id) { ASSERT(Token::IsEqualityOperator(kind)); + SetInputAt(0, left); + SetInputAt(1, right); set_operation_cid(cid); } @@ -3151,7 +3190,7 @@ class EqualityCompareInstr : public ComparisonInstr { }; -class RelationalOpInstr : public ComparisonInstr { +class RelationalOpInstr : public TemplateComparison<2, NoThrow, Pure> { public: RelationalOpInstr(TokenPosition token_pos, Token::Kind kind, @@ -3159,8 +3198,10 @@ class RelationalOpInstr : public ComparisonInstr { Value* right, intptr_t cid, intptr_t deopt_id) - : ComparisonInstr(token_pos, kind, left, right, deopt_id) { + : TemplateComparison(token_pos, kind, deopt_id) { ASSERT(Token::IsRelationalOperator(kind)); + SetInputAt(0, left); + SetInputAt(1, right); set_operation_cid(cid); } @@ -5343,24 +5384,21 @@ class BinaryDoubleOpInstr : public TemplateDefinition<2, NoThrow, Pure> { }; -class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> { +class DoubleTestOpInstr : public TemplateComparison<1, NoThrow, Pure> { public: DoubleTestOpInstr(MethodRecognizer::Kind op_kind, - Value* d, + Value* value, intptr_t deopt_id, TokenPosition token_pos) - : TemplateDefinition(deopt_id), - op_kind_(op_kind), - token_pos_(token_pos) { - SetInputAt(0, d); + : TemplateComparison(token_pos, Token::kEQ, deopt_id), + op_kind_(op_kind) { + SetInputAt(0, value); } - Value* value() const { return inputs_[0]; } + Value* value() const { return InputAt(0); } MethodRecognizer::Kind op_kind() const { return op_kind_; } - virtual TokenPosition token_pos() const { return token_pos_; } - virtual bool CanDeoptimize() const { return false; } virtual Representation RequiredInputRepresentation(intptr_t idx) const { @@ -5368,12 +5406,6 @@ class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> { return kUnboxedDouble; } - virtual intptr_t DeoptimizationTarget() const { - // Direct access since this instruction cannot deoptimize, and the deopt-id - // was inherited from another instruction that could deoptimize. - return GetDeoptId(); - } - PRINT_OPERANDS_TO_SUPPORT DECLARE_INSTRUCTION(DoubleTestOp) @@ -5382,12 +5414,20 @@ class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> { virtual Definition* Canonicalize(FlowGraph* flow_graph); virtual bool AttributesEqual(Instruction* other) const { - return op_kind_ == other->AsDoubleTestOp()->op_kind(); + return op_kind_ == other->AsDoubleTestOp()->op_kind() + && ComparisonInstr::AttributesEqual(other); } + virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right); + + virtual void EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch); + + virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels); + private: const MethodRecognizer::Kind op_kind_; - const TokenPosition token_pos_; DISALLOW_COPY_AND_ASSIGN(DoubleTestOpInstr); }; diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc index 65507388436..b6390b66306 100644 --- a/runtime/vm/intermediate_language_arm.cc +++ b/runtime/vm/intermediate_language_arm.cc @@ -124,6 +124,8 @@ static Condition NegateCondition(Condition condition) { case LS: return HI; case HI: return LS; case CS: return CC; + case VC: return VS; + case VS: return VC; default: UNREACHABLE(); return EQ; @@ -4154,31 +4156,57 @@ LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone, } -void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - ASSERT(compiler->is_optimizing()); +Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels) { const DRegister value = EvenDRegisterOf(locs()->in(0).fpu_reg()); const Register result = locs()->out(0).reg(); + const bool is_negated = kind() != Token::kEQ; if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { - __ LoadObject(result, Bool::False()); __ vcmpd(value, value); __ vmstat(); - __ LoadObject(result, Bool::True(), VS); + return is_negated ? VC : VS; } else { ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite); Label done; // TMP <- value[0:31], result <- value[32:63] __ vmovrrd(TMP, result, value); __ cmp(TMP, Operand(0)); - __ LoadObject(result, Bool::False(), NE); - __ b(&done, NE); + __ b(is_negated ? labels.true_label : labels.false_label, NE); // Mask off the sign bit. __ AndImmediate(result, result, 0x7FFFFFFF); // Compare with +infinity. __ CompareImmediate(result, 0x7FF00000); - __ LoadObject(result, Bool::False(), NE); - __ b(&done, NE); + return is_negated ? NE : EQ; + } +} +void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch) { + ASSERT(compiler->is_optimizing()); + BranchLabels labels = compiler->CreateBranchLabels(branch); + Condition true_condition = EmitComparisonCode(compiler, labels); + EmitBranchOnCondition(compiler, true_condition, labels); +} + + +void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + ASSERT(compiler->is_optimizing()); + Label is_true, is_false; + BranchLabels labels = { &is_true, &is_false, &is_false }; + Condition true_condition = EmitComparisonCode(compiler, labels); + const Register result = locs()->out(0).reg(); + if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { + __ LoadObject(result, Bool::True(), true_condition); + __ LoadObject(result, Bool::False(), NegateCondition(true_condition)); + } else { + ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite); + EmitBranchOnCondition(compiler, true_condition, labels); + Label done; + __ Bind(&is_false); + __ LoadObject(result, Bool::False()); + __ b(&done); + __ Bind(&is_true); __ LoadObject(result, Bool::True()); __ Bind(&done); } diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc index 22fac288637..8968d7d67ce 100644 --- a/runtime/vm/intermediate_language_arm64.cc +++ b/runtime/vm/intermediate_language_arm64.cc @@ -123,6 +123,8 @@ static Condition NegateCondition(Condition condition) { case LS: return HI; case HI: return LS; case CS: return CC; + case VS: return VC; + case VC: return VS; default: UNREACHABLE(); return EQ; @@ -3485,34 +3487,63 @@ void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone, bool opt) const { const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; + const intptr_t kNumTemps = + op_kind() == MethodRecognizer::kDouble_getIsInfinite ? 1 : 0; LocationSummary* summary = new(zone) LocationSummary( zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresFpuRegister()); + if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) { + summary->set_temp(0, Location::RequiresRegister()); + } summary->set_out(0, Location::RequiresRegister()); return summary; } -void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { +Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels) { ASSERT(compiler->is_optimizing()); const VRegister value = locs()->in(0).fpu_reg(); - const Register result = locs()->out(0).reg(); + const bool is_negated = kind() != Token::kEQ; if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { __ fcmpd(value, value); - __ LoadObject(result, Bool::False()); - __ LoadObject(TMP, Bool::True()); - __ csel(result, TMP, result, VS); + return is_negated ? VC : VS; } else { ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite); - __ vmovrd(result, value, 0); + const Register temp = locs()->temp(0).reg(); + __ vmovrd(temp, value, 0); // Mask off the sign. - __ AndImmediate(result, result, 0x7FFFFFFFFFFFFFFFLL); + __ AndImmediate(temp, temp, 0x7FFFFFFFFFFFFFFFLL); // Compare with +infinity. - __ CompareImmediate(result, 0x7FF0000000000000LL); + __ CompareImmediate(temp, 0x7FF0000000000000LL); + return is_negated ? NE : EQ; + } +} + + +void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch) { + ASSERT(compiler->is_optimizing()); + BranchLabels labels = compiler->CreateBranchLabels(branch); + Condition true_condition = EmitComparisonCode(compiler, labels); + EmitBranchOnCondition(compiler, true_condition, labels); +} + + +void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + ASSERT(compiler->is_optimizing()); + Label is_true, is_false; + BranchLabels labels = { &is_true, &is_false, &is_false }; + Condition true_condition = EmitComparisonCode(compiler, labels); + const Register result = locs()->out(0).reg(); + if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { __ LoadObject(result, Bool::False()); __ LoadObject(TMP, Bool::True()); - __ csel(result, TMP, result, EQ); + __ csel(result, TMP, result, true_condition); + } else { + __ LoadObject(result, Bool::False()); + __ LoadObject(TMP, Bool::True()); + __ csel(result, TMP, result, true_condition); } } diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc index 26c8fec3595..e239229032e 100644 --- a/runtime/vm/intermediate_language_dbc.cc +++ b/runtime/vm/intermediate_language_dbc.cc @@ -1649,20 +1649,51 @@ EMIT_NATIVE_CODE(BinaryDoubleOp, 2, Location::RequiresRegister()) { } -EMIT_NATIVE_CODE(DoubleTestOp, 1, Location::RequiresRegister()) { +Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels) { + UNREACHABLE(); + return Condition(); +} + + +void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch) { ASSERT(compiler->is_optimizing()); + BranchLabels labels = compiler->CreateBranchLabels(branch); const Register value = locs()->in(0).reg(); - const Register result = locs()->out(0).reg(); switch (op_kind()) { case MethodRecognizer::kDouble_getIsNaN: - __ DoubleIsNaN(result, value); + __ DoubleIsNaN(value); break; case MethodRecognizer::kDouble_getIsInfinite: - __ DoubleIsInfinite(result, value); + __ DoubleIsInfinite(value); break; default: UNREACHABLE(); } + const bool is_negated = kind() != Token::kEQ; + EmitBranchOnCondition( + compiler, is_negated ? NEXT_IS_FALSE : NEXT_IS_TRUE, labels); +} + + +EMIT_NATIVE_CODE(DoubleTestOp, 1, Location::RequiresRegister()) { + ASSERT(compiler->is_optimizing()); + const Register value = locs()->in(0).reg(); + const Register result = locs()->out(0).reg(); + const bool is_negated = kind() != Token::kEQ; + __ LoadConstant(result, is_negated ? Bool::True() : Bool::False()); + switch (op_kind()) { + case MethodRecognizer::kDouble_getIsNaN: + __ DoubleIsNaN(value); + break; + case MethodRecognizer::kDouble_getIsInfinite: + __ DoubleIsInfinite(value); + break; + default: + UNREACHABLE(); + } + __ LoadConstant(result, is_negated ? Bool::False() : Bool::True()); } @@ -1832,8 +1863,7 @@ static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler, LocationSummary* locs, - Token::Kind kind, - BranchLabels labels) { + Token::Kind kind) { const Register left = locs->in(0).reg(); const Register right = locs->in(1).reg(); Token::Kind comparison = kind; @@ -1854,7 +1884,7 @@ Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, return EmitSmiComparisonOp(compiler, locs(), kind(), labels); } else { ASSERT(operation_cid() == kDoubleCid); - return EmitDoubleComparisonOp(compiler, locs(), kind(), labels); + return EmitDoubleComparisonOp(compiler, locs(), kind()); } } @@ -1890,7 +1920,7 @@ Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, return EmitSmiComparisonOp(compiler, locs(), kind(), labels); } else { ASSERT(operation_cid() == kDoubleCid); - return EmitDoubleComparisonOp(compiler, locs(), kind(), labels); + return EmitDoubleComparisonOp(compiler, locs(), kind()); } } diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc index 965cbeb998a..10293010ca3 100644 --- a/runtime/vm/intermediate_language_ia32.cc +++ b/runtime/vm/intermediate_language_ia32.cc @@ -388,6 +388,8 @@ static Condition NegateCondition(Condition condition) { case BELOW_EQUAL: return ABOVE; case ABOVE: return BELOW_EQUAL; case ABOVE_EQUAL: return BELOW; + case PARITY_ODD: return PARITY_EVEN; + case PARITY_EVEN: return PARITY_ODD; default: UNIMPLEMENTED(); return EQUAL; @@ -3902,53 +3904,79 @@ void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone, bool opt) const { const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; + const intptr_t kNumTemps = + (op_kind() == MethodRecognizer::kDouble_getIsInfinite) ? 1 : 0; LocationSummary* summary = new(zone) LocationSummary( zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresFpuRegister()); + if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) { + summary->set_temp(0, Location::RequiresRegister()); + } summary->set_out(0, Location::RequiresRegister()); return summary; } -void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { +Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels) { ASSERT(compiler->is_optimizing()); const XmmRegister value = locs()->in(0).fpu_reg(); - const Register result = locs()->out(0).reg(); + const bool is_negated = kind() != Token::kEQ; if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { Label is_nan; - __ LoadObject(result, Bool::True()); __ comisd(value, value); - __ j(PARITY_EVEN, &is_nan, Assembler::kNearJump); - __ LoadObject(result, Bool::False()); - __ Bind(&is_nan); + return is_negated ? PARITY_ODD : PARITY_EVEN; } else { ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite); - Label not_inf, done; + const Register temp = locs()->temp(0).reg(); + Label check_upper; __ AddImmediate(ESP, Immediate(-kDoubleSize)); __ movsd(Address(ESP, 0), value); - __ movl(result, Address(ESP, 0)); + __ movl(temp, Address(ESP, 0)); // If the low word isn't zero, then it isn't infinity. - __ cmpl(result, Immediate(0)); - __ j(NOT_EQUAL, ¬_inf, Assembler::kNearJump); - // Check the high word. - __ movl(result, Address(ESP, kWordSize)); - // Mask off sign bit. - __ andl(result, Immediate(0x7FFFFFFF)); - // Compare with +infinity. - __ cmpl(result, Immediate(0x7FF00000)); - __ j(NOT_EQUAL, ¬_inf, Assembler::kNearJump); - __ LoadObject(result, Bool::True()); - __ jmp(&done); - - __ Bind(¬_inf); - __ LoadObject(result, Bool::False()); - __ Bind(&done); + __ cmpl(temp, Immediate(0)); + __ j(EQUAL, &check_upper, Assembler::kNearJump); __ AddImmediate(ESP, Immediate(kDoubleSize)); + __ jmp(is_negated ? labels.true_label : labels.false_label); + __ Bind(&check_upper); + // Check the high word. + __ movl(temp, Address(ESP, kWordSize)); + __ AddImmediate(ESP, Immediate(kDoubleSize)); + // Mask off sign bit. + __ andl(temp, Immediate(0x7FFFFFFF)); + // Compare with +infinity. + __ cmpl(temp, Immediate(0x7FF00000)); + return is_negated ? NOT_EQUAL : EQUAL; } } +void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch) { + ASSERT(compiler->is_optimizing()); + BranchLabels labels = compiler->CreateBranchLabels(branch); + Condition true_condition = EmitComparisonCode(compiler, labels); + EmitBranchOnCondition(compiler, true_condition, labels); +} + + +void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + Label is_true, is_false; + BranchLabels labels = { &is_true, &is_false, &is_false }; + Condition true_condition = EmitComparisonCode(compiler, labels); + EmitBranchOnCondition(compiler, true_condition, labels); + + Register result = locs()->out(0).reg(); + Label done; + __ Bind(&is_false); + __ LoadObject(result, Bool::False()); + __ jmp(&done); + __ Bind(&is_true); + __ LoadObject(result, Bool::True()); + __ Bind(&done); +} + + LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Zone* zone, bool opt) const { const intptr_t kNumInputs = 2; diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc index 793c1b43d93..91d0ad5a808 100644 --- a/runtime/vm/intermediate_language_mips.cc +++ b/runtime/vm/intermediate_language_mips.cc @@ -3704,38 +3704,78 @@ LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone, } -void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - ASSERT(compiler->is_optimizing()); +Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels) { const DRegister value = locs()->in(0).fpu_reg(); - const Register result = locs()->out(0).reg(); + const bool is_negated = kind() != Token::kEQ; if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { - Label is_not_nan; - __ LoadObject(result, Bool::False()); __ cund(value, value); - __ bc1f(&is_not_nan); - __ LoadObject(result, Bool::True()); - __ Bind(&is_not_nan); + if (labels.fall_through == labels.true_label) { + if (is_negated) { + __ bc1t(labels.false_label); + } else { + __ bc1f(labels.false_label); + } + } else if (labels.fall_through == labels.false_label) { + if (is_negated) { + __ bc1f(labels.true_label); + } else { + __ bc1t(labels.true_label); + } + } else { + if (is_negated) { + __ bc1t(labels.false_label); + } else { + __ bc1f(labels.false_label); + } + __ b(labels.true_label); + } + return Condition(); // Unused. } else { ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite); - Label not_inf, done; - __ mfc1(TMP, EvenFRegisterOf(value)); - __ mfc1(result, OddFRegisterOf(value)); + __ mfc1(CMPRES1, EvenFRegisterOf(value)); // If the low word isn't zero, then it isn't infinity. - __ bne(TMP, ZR, ¬_inf); + __ bne(CMPRES1, ZR, is_negated ? labels.true_label : labels.false_label); + __ mfc1(CMPRES1, OddFRegisterOf(value)); // Mask off the sign bit. - __ AndImmediate(result, result, 0x7FFFFFFF); + __ AndImmediate(CMPRES1, CMPRES1, 0x7FFFFFFF); // Compare with +infinity. - __ BranchNotEqual(result, Immediate(0x7FF00000), ¬_inf); - - __ LoadObject(result, Bool::True()); - __ b(&done); - - __ Bind(¬_inf); - __ LoadObject(result, Bool::False()); - __ Bind(&done); + __ LoadImmediate(CMPRES2, 0x7FF00000); + return Condition(CMPRES1, CMPRES2, is_negated ? NE : EQ); } } +void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch) { + ASSERT(compiler->is_optimizing()); + BranchLabels labels = compiler->CreateBranchLabels(branch); + Condition true_condition = EmitComparisonCode(compiler, labels); + // Branches for isNaN are emitted in EmitComparisonCode already. + if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) { + EmitBranchOnCondition(compiler, true_condition, labels); + } +} + + +void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + Label is_true, is_false; + BranchLabels labels = { &is_true, &is_false, &is_false }; + Condition true_condition = EmitComparisonCode(compiler, labels); + // Branches for isNaN are emitted in EmitComparisonCode already. + if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) { + EmitBranchOnCondition(compiler, true_condition, labels); + } + const Register result = locs()->out(0).reg(); + Label done; + __ Comment("return bool"); + __ Bind(&is_false); + __ LoadObject(result, Bool::False()); + __ b(&done); + __ Bind(&is_true); + __ LoadObject(result, Bool::True()); + __ Bind(&done); +} + LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Zone* zone, bool opt) const { diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc index 2b75b2acf41..96f288a2192 100644 --- a/runtime/vm/intermediate_language_x64.cc +++ b/runtime/vm/intermediate_language_x64.cc @@ -121,6 +121,8 @@ static Condition NegateCondition(Condition condition) { case BELOW_EQUAL: return ABOVE; case ABOVE: return BELOW_EQUAL; case ABOVE_EQUAL: return BELOW; + case PARITY_EVEN: return PARITY_ODD; + case PARITY_ODD: return PARITY_EVEN; default: UNIMPLEMENTED(); return EQUAL; @@ -3763,49 +3765,70 @@ void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone, bool opt) const { const intptr_t kNumInputs = 1; - const intptr_t kNumTemps = 0; + const intptr_t kNumTemps = + (op_kind() == MethodRecognizer::kDouble_getIsInfinite) ? 1 : 0; LocationSummary* summary = new(zone) LocationSummary( zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresFpuRegister()); + if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) { + summary->set_temp(0, Location::RequiresRegister()); + } summary->set_out(0, Location::RequiresRegister()); return summary; } -void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { +Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, + BranchLabels labels) { ASSERT(compiler->is_optimizing()); const XmmRegister value = locs()->in(0).fpu_reg(); - const Register result = locs()->out(0).reg(); + const bool is_negated = kind() != Token::kEQ; if (op_kind() == MethodRecognizer::kDouble_getIsNaN) { Label is_nan; - __ LoadObject(result, Bool::True()); __ comisd(value, value); - __ j(PARITY_EVEN, &is_nan, Assembler::kNearJump); - __ LoadObject(result, Bool::False()); - __ Bind(&is_nan); + return is_negated ? PARITY_ODD : PARITY_EVEN; } else { ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite); - Label is_inf, done; + const Register temp = locs()->temp(0).reg(); __ AddImmediate(RSP, Immediate(-kDoubleSize)); __ movsd(Address(RSP, 0), value); - __ movq(result, Address(RSP, 0)); - // Mask off the sign. - __ AndImmediate(result, Immediate(0x7FFFFFFFFFFFFFFFLL)); - // Compare with +infinity. - __ CompareImmediate(result, Immediate(0x7FF0000000000000LL)); - __ j(EQUAL, &is_inf, Assembler::kNearJump); - __ LoadObject(result, Bool::False()); - __ jmp(&done); - - __ Bind(&is_inf); - __ LoadObject(result, Bool::True()); - - __ Bind(&done); + __ movq(temp, Address(RSP, 0)); __ AddImmediate(RSP, Immediate(kDoubleSize)); + // Mask off the sign. + __ AndImmediate(temp, Immediate(0x7FFFFFFFFFFFFFFFLL)); + // Compare with +infinity. + __ CompareImmediate(temp, Immediate(0x7FF0000000000000LL)); + return is_negated ? NOT_EQUAL : EQUAL; } } +void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, + BranchInstr* branch) { + ASSERT(compiler->is_optimizing()); + BranchLabels labels = compiler->CreateBranchLabels(branch); + Condition true_condition = EmitComparisonCode(compiler, labels); + EmitBranchOnCondition(compiler, true_condition, labels); +} + + +void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + Label is_true, is_false; + BranchLabels labels = { &is_true, &is_false, &is_false }; + Condition true_condition = EmitComparisonCode(compiler, labels); + EmitBranchOnCondition(compiler, true_condition, labels); + + Register result = locs()->out(0).reg(); + Label done; + __ Bind(&is_false); + __ LoadObject(result, Bool::False()); + __ jmp(&done); + __ Bind(&is_true); + __ LoadObject(result, Bool::True()); + __ Bind(&done); +} + + LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Zone* zone, bool opt) const { const intptr_t kNumInputs = 2; diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc index c3998aff11a..5161e579371 100644 --- a/runtime/vm/simulator_dbc.cc +++ b/runtime/vm/simulator_dbc.cc @@ -2229,16 +2229,20 @@ RawObject* Simulator::Call(const Code& code, } { - BYTECODE(DoubleIsNaN, A_D); - const double v = bit_cast(FP[rD]); - FP[rA] = isnan(v) ? true_value : false_value; + BYTECODE(DoubleIsNaN, A); + const double v = bit_cast(FP[rA]); + if (!isnan(v)) { + pc++; + } DISPATCH(); } { - BYTECODE(DoubleIsInfinite, A_D); - const double v = bit_cast(FP[rD]); - FP[rA] = isinf(v) ? true_value : false_value; + BYTECODE(DoubleIsInfinite, A); + const double v = bit_cast(FP[rA]); + if (!isinf(v)) { + pc++; + } DISPATCH(); }