VM: Enable branch merging of isnan, isinf.

More general ComparisonInstr by introducing TemplateComparison.

R=zra@google.com

Review URL: https://codereview.chromium.org/2463593002 .
This commit is contained in:
Florian Schneider 2016-10-31 20:21:19 +01:00
parent ba382b6ce4
commit b1dfa2aee1
11 changed files with 379 additions and 145 deletions

View file

@ -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();

View file

@ -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, ___, ___, ___) \

View file

@ -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(),

View file

@ -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<intptr_t N,
typename ThrowsTrait,
template<typename Impure, typename Pure> 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<ComparisonInstr, PureComparison>::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<Value*, N> 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<intptr_t>& 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<intptr_t>& 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);
};

View file

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

View file

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

View file

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

View file

@ -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, &not_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, &not_inf, Assembler::kNearJump);
__ LoadObject(result, Bool::True());
__ jmp(&done);
__ Bind(&not_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;

View file

@ -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, &not_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), &not_inf);
__ LoadObject(result, Bool::True());
__ b(&done);
__ Bind(&not_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 {

View file

@ -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;

View file

@ -2229,16 +2229,20 @@ RawObject* Simulator::Call(const Code& code,
}
{
BYTECODE(DoubleIsNaN, A_D);
const double v = bit_cast<double, RawObject*>(FP[rD]);
FP[rA] = isnan(v) ? true_value : false_value;
BYTECODE(DoubleIsNaN, A);
const double v = bit_cast<double, RawObject*>(FP[rA]);
if (!isnan(v)) {
pc++;
}
DISPATCH();
}
{
BYTECODE(DoubleIsInfinite, A_D);
const double v = bit_cast<double, RawObject*>(FP[rD]);
FP[rA] = isinf(v) ? true_value : false_value;
BYTECODE(DoubleIsInfinite, A);
const double v = bit_cast<double, RawObject*>(FP[rA]);
if (!isinf(v)) {
pc++;
}
DISPATCH();
}