mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 16:44:59 +00:00
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:
parent
ba382b6ce4
commit
b1dfa2aee1
|
@ -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();
|
||||
|
|
|
@ -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, ___, ___, ___) \
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue