Index: runtime/vm/intermediate_language.h |
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h |
index ff3822cf9754846491807a5a7f95e99c5ca8b044..efa6455a2205157d06d9107007a744d2bf2636b8 100644 |
--- a/runtime/vm/intermediate_language.h |
+++ b/runtime/vm/intermediate_language.h |
@@ -453,7 +453,7 @@ class EmbeddedArray<T, 0> { |
M(OneByteStringFromCharCode) \ |
M(StringInterpolate) \ |
M(InvokeMathCFunction) \ |
- M(MergedMath) \ |
+ M(TruncDivMod) \ |
M(GuardFieldClass) \ |
M(GuardFieldLength) \ |
M(IfThenElse) \ |
@@ -6929,7 +6929,8 @@ class BinarySmiOpInstr : public BinaryIntegerOpInstr { |
Value* left, |
Value* right, |
intptr_t deopt_id) |
- : BinaryIntegerOpInstr(op_kind, left, right, deopt_id) {} |
+ : BinaryIntegerOpInstr(op_kind, left, right, deopt_id), |
+ right_range_(NULL) {} |
virtual bool ComputeCanDeoptimize() const; |
@@ -6938,7 +6939,11 @@ class BinarySmiOpInstr : public BinaryIntegerOpInstr { |
DECLARE_INSTRUCTION(BinarySmiOp) |
+ Range* right_range() const { return right_range_; } |
+ |
private: |
+ Range* right_range_; |
+ |
DISALLOW_COPY_AND_ASSIGN(BinarySmiOpInstr); |
}; |
@@ -6967,7 +6972,11 @@ class BinaryInt32OpInstr : public BinaryIntegerOpInstr { |
case Token::kSHL: |
case Token::kSHR: |
- return right->BindsToConstant(); |
+ if (right->BindsToConstant() && right->BoundConstant().IsSmi()) { |
+ const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); |
+ return 0 <= value && value < kBitsPerWord; |
+ } |
+ return false; |
default: |
return false; |
@@ -7089,10 +7098,13 @@ class ShiftMintOpInstr : public BinaryIntegerOpInstr { |
Value* left, |
Value* right, |
intptr_t deopt_id) |
- : BinaryIntegerOpInstr(op_kind, left, right, deopt_id) { |
+ : BinaryIntegerOpInstr(op_kind, left, right, deopt_id), |
+ shift_range_(NULL) { |
ASSERT((op_kind == Token::kSHR) || (op_kind == Token::kSHL)); |
} |
+ Range* shift_range() const { return shift_range_; } |
+ |
virtual bool ComputeCanDeoptimize() const { |
return has_shift_count_check() || |
(can_overflow() && (op_kind() == Token::kSHL)); |
@@ -7111,8 +7123,11 @@ class ShiftMintOpInstr : public BinaryIntegerOpInstr { |
DECLARE_INSTRUCTION(ShiftMintOp) |
private: |
+ static const intptr_t kMintShiftCountLimit = 63; |
bool has_shift_count_check() const; |
+ Range* shift_range_; |
+ |
DISALLOW_COPY_AND_ASSIGN(ShiftMintOpInstr); |
}; |
@@ -7545,90 +7560,45 @@ class ExtractNthOutputInstr : public TemplateDefinition<1, NoThrow, Pure> { |
}; |
-class MergedMathInstr : public PureDefinition { |
+class TruncDivModInstr : public TemplateDefinition<2, NoThrow, Pure> { |
public: |
- enum Kind { |
- kTruncDivMod, |
- }; |
- |
- MergedMathInstr(ZoneGrowableArray<Value*>* inputs, |
- intptr_t original_deopt_id, |
- MergedMathInstr::Kind kind); |
- |
- static intptr_t InputCountFor(MergedMathInstr::Kind kind) { |
- if (kind == kTruncDivMod) { |
- return 2; |
- } else { |
- UNIMPLEMENTED(); |
- return -1; |
- } |
- } |
- |
- MergedMathInstr::Kind kind() const { return kind_; } |
- |
- virtual intptr_t InputCount() const { return inputs_->length(); } |
- |
- virtual Value* InputAt(intptr_t i) const { return (*inputs_)[i]; } |
+ TruncDivModInstr(Value* lhs, Value* rhs, intptr_t deopt_id); |
- static intptr_t OutputIndexOf(MethodRecognizer::Kind kind); |
static intptr_t OutputIndexOf(Token::Kind token); |
virtual CompileType ComputeType() const; |
- virtual bool ComputeCanDeoptimize() const { |
- if (kind_ == kTruncDivMod) { |
- return true; |
- } else { |
- UNIMPLEMENTED(); |
- return false; |
- } |
- } |
+ virtual bool ComputeCanDeoptimize() const { return true; } |
- virtual Representation representation() const { |
- if (kind_ == kTruncDivMod) { |
- return kPairOfTagged; |
- } else { |
- UNIMPLEMENTED(); |
- return kTagged; |
- } |
- } |
+ virtual Representation representation() const { return kPairOfTagged; } |
virtual Representation RequiredInputRepresentation(intptr_t idx) const { |
ASSERT((0 <= idx) && (idx < InputCount())); |
- if (kind_ == kTruncDivMod) { |
- return kTagged; |
- } else { |
- UNIMPLEMENTED(); |
- return kTagged; |
- } |
+ return kTagged; |
} |
virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); } |
- DECLARE_INSTRUCTION(MergedMath) |
- |
- virtual bool AttributesEqual(Instruction* other) const { |
- MergedMathInstr* other_invoke = other->AsMergedMath(); |
- return other_invoke->kind() == kind(); |
- } |
- |
- virtual bool MayThrow() const { return false; } |
+ DECLARE_INSTRUCTION(TruncDivMod) |
- static const char* KindToCString(MergedMathInstr::Kind kind) { |
- if (kind == kTruncDivMod) return "TruncDivMod"; |
- UNIMPLEMENTED(); |
- return ""; |
- } |
+ virtual bool AttributesEqual(Instruction* other) const { return true; } |
PRINT_OPERANDS_TO_SUPPORT |
private: |
- virtual void RawSetInputAt(intptr_t i, Value* value) { |
- (*inputs_)[i] = value; |
+ Range* divisor_range() const { |
+ // Note: this range is only used to remove check for zero divisor from |
+ // the emitted pattern. It is not used for deciding whether instruction |
+ // will deoptimize or not - that is why it is ok to access range of |
+ // the definition directly. Otherwise range analysis or another pass |
+ // needs to cache range of the divisor in the operation to prevent |
+ // bugs when range information gets out of sync with the final decision |
+ // whether some instruction can deoptimize or not made in |
+ // EliminateEnvironments(). |
+ return InputAt(1)->definition()->range(); |
} |
- ZoneGrowableArray<Value*>* inputs_; |
- MergedMathInstr::Kind kind_; |
- DISALLOW_COPY_AND_ASSIGN(MergedMathInstr); |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TruncDivModInstr); |
}; |