Index: src/hydrogen-instructions.h |
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h |
index 7554fd85bad5a136e387698eb704159008be7bdd..e564637a37e5bb7d532c995a788455dba31ca2b0 100644 |
--- a/src/hydrogen-instructions.h |
+++ b/src/hydrogen-instructions.h |
@@ -39,6 +39,7 @@ |
#include "v8utils.h" |
#include "zone.h" |
+ |
namespace v8 { |
namespace internal { |
@@ -3050,12 +3051,279 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { |
}; |
+class InductionVariableData; |
+ |
+ |
+struct InductionVariableLimitUpdate { |
+ InductionVariableData* updated_variable; |
+ HValue* limit; |
+ bool limit_is_upper; |
+ bool limit_is_included; |
+ |
+ InductionVariableLimitUpdate() |
+ : updated_variable(NULL), limit(NULL), |
+ limit_is_upper(false), limit_is_included(false) {} |
+}; |
+ |
+ |
+class HBoundsCheck; |
+class HPhi; |
+class HConstant; |
+class HBitwise; |
+ |
+ |
+class InductionVariableData : public ZoneObject { |
+ public: |
+ class InductionVariableCheck : public ZoneObject { |
+ public: |
+ HBoundsCheck* check() { return check_; } |
+ InductionVariableCheck* next() { return next_; } |
+ bool HasUpperLimit() { return upper_limit_ >= 0; } |
+ int32_t upper_limit() { |
+ ASSERT(HasUpperLimit()); |
+ return upper_limit_; |
+ } |
+ void set_upper_limit(int32_t upper_limit) { |
+ upper_limit_ = upper_limit; |
+ } |
+ |
+ bool processed() { return processed_; } |
+ void set_processed() { processed_ = true; } |
+ |
+ InductionVariableCheck(HBoundsCheck* check, |
+ InductionVariableCheck* next, |
+ int32_t upper_limit = kNoLimit) |
+ : check_(check), next_(next), upper_limit_(upper_limit), |
+ processed_(false) {} |
+ |
+ private: |
+ HBoundsCheck* check_; |
+ InductionVariableCheck* next_; |
+ int32_t upper_limit_; |
+ bool processed_; |
+ }; |
+ |
+ class ChecksRelatedToLength : public ZoneObject { |
+ public: |
+ HValue* length() { return length_; } |
+ ChecksRelatedToLength* next() { return next_; } |
+ InductionVariableCheck* checks() { return checks_; } |
+ |
+ void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); |
+ void CloseCurrentBlock(); |
+ |
+ ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next) |
+ : length_(length), next_(next), checks_(NULL), |
+ first_check_in_block_(NULL), |
+ added_index_(NULL), |
+ added_constant_(NULL), |
+ current_and_mask_in_block_(0), |
+ current_or_mask_in_block_(0) {} |
+ |
+ private: |
+ void UseNewIndexInCurrentBlock(Token::Value token, |
+ int32_t mask, |
+ HValue* index_base, |
+ HValue* context); |
+ |
+ HBoundsCheck* first_check_in_block() { return first_check_in_block_; } |
+ HBitwise* added_index() { return added_index_; } |
+ void set_added_index(HBitwise* index) { added_index_ = index; } |
+ HConstant* added_constant() { return added_constant_; } |
+ void set_added_constant(HConstant* constant) { added_constant_ = constant; } |
+ int32_t current_and_mask_in_block() { return current_and_mask_in_block_; } |
+ int32_t current_or_mask_in_block() { return current_or_mask_in_block_; } |
+ int32_t current_upper_limit() { return current_upper_limit_; } |
+ |
+ HValue* length_; |
+ ChecksRelatedToLength* next_; |
+ InductionVariableCheck* checks_; |
+ |
+ HBoundsCheck* first_check_in_block_; |
+ HBitwise* added_index_; |
+ HConstant* added_constant_; |
+ int32_t current_and_mask_in_block_; |
+ int32_t current_or_mask_in_block_; |
+ int32_t current_upper_limit_; |
+ }; |
+ |
+ struct LimitFromPredecessorBlock { |
+ InductionVariableData* variable; |
+ Token::Value token; |
+ HValue* limit; |
+ HBasicBlock* other_target; |
+ |
+ bool LimitIsValid() { return token != Token::ILLEGAL; } |
+ |
+ bool LimitIsIncluded() { |
+ return Token::IsEqualityOp(token) || |
+ token == Token::GTE || token == Token::LTE; |
+ } |
+ bool LimitIsUpper() { |
+ return token == Token::LTE || token == Token::LT || token == Token::NE; |
+ } |
+ |
+ LimitFromPredecessorBlock() |
+ : variable(NULL), |
+ token(Token::ILLEGAL), |
+ limit(NULL), |
+ other_target(NULL) {} |
+ }; |
+ |
+ static const int32_t kNoLimit = -1; |
+ |
+ static InductionVariableData* ExaminePhi(HPhi* phi); |
+ static void ComputeLimitFromPredecessorBlock( |
+ HBasicBlock* block, |
+ LimitFromPredecessorBlock* result); |
+ static bool ComputeInductionVariableLimit( |
+ HBasicBlock* block, |
+ InductionVariableLimitUpdate* additional_limit); |
+ |
+ struct BitwiseDecompositionResult { |
+ HValue* base; |
+ int32_t and_mask; |
+ int32_t or_mask; |
+ HValue* context; |
+ |
+ BitwiseDecompositionResult() |
+ : base(NULL), and_mask(0), or_mask(0), context(NULL) {} |
+ }; |
+ static void DecomposeBitwise(HValue* value, |
+ BitwiseDecompositionResult* result); |
+ |
+ void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); |
+ |
+ bool CheckIfBranchIsLoopGuard(Token::Value token, |
+ HBasicBlock* current_branch, |
+ HBasicBlock* other_branch); |
+ |
+ void UpdateAdditionalLimit(InductionVariableLimitUpdate* update) { |
titzer
2013/07/11 16:39:10
Also put this into the .cc file please.
And why a
Massi
2013/07/12 08:20:24
Done.
We are swapping because of the need for back
|
+ ASSERT(update->updated_variable == this); |
+ if (update->limit_is_upper) { |
+ swap(&additional_upper_limit_, &update->limit); |
+ swap(&additional_upper_limit_is_included_, &update->limit_is_included); |
+ } else { |
+ swap(&additional_lower_limit_, &update->limit); |
+ swap(&additional_lower_limit_is_included_, &update->limit_is_included); |
+ } |
+ } |
+ |
+ HPhi* phi() { return phi_; } |
+ HValue* base() { return base_; } |
+ int32_t increment() { return increment_; } |
+ HValue* limit() { return limit_; } |
+ bool limit_included() { return limit_included_; } |
+ HBasicBlock* limit_validity() { return limit_validity_; } |
+ HBasicBlock* induction_exit_block() { return induction_exit_block_; } |
+ HBasicBlock* induction_exit_target() { return induction_exit_target_; } |
+ ChecksRelatedToLength* checks() { return checks_; } |
+ HValue* additional_upper_limit() { return additional_upper_limit_; } |
+ bool additional_upper_limit_is_included() { |
+ return additional_upper_limit_is_included_; |
+ } |
+ HValue* additional_lower_limit() { return additional_lower_limit_; } |
+ bool additional_lower_limit_is_included() { |
+ return additional_lower_limit_is_included_; |
+ } |
+ |
+ bool lower_limit_is_non_negative_constant() { |
titzer
2013/07/11 16:39:10
hacker_style is supposedly only for accessors.
Massi
2013/07/12 08:20:24
Done.
|
+ if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) { |
+ return true; |
+ } |
+ if (additional_lower_limit() != NULL && |
+ additional_lower_limit()->IsInteger32Constant() && |
+ additional_lower_limit()->GetInteger32Constant() >= 0) { |
+ // Ignoring the corner case of !additional_lower_limit_is_included() |
+ // is safe, handling it adds unneeded complexity. |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask) { |
titzer
2013/07/11 16:39:10
Put this one in the .cc file.
Massi
2013/07/12 08:20:24
Done.
|
+ // Should be Smi::kMaxValue but it must fit 32 bits; lower is safe anyway. |
+ const int32_t MAX_LIMIT = 1 << 30; |
+ |
+ int32_t result = MAX_LIMIT; |
+ |
+ if (limit() != NULL && |
+ limit()->IsInteger32Constant()) { |
+ int32_t limit_value = limit()->GetInteger32Constant(); |
+ if (!limit_included()) { |
+ limit_value--; |
+ } |
+ if (limit_value < result) result = limit_value; |
+ } |
+ |
+ if (additional_upper_limit() != NULL && |
+ additional_upper_limit()->IsInteger32Constant()) { |
+ int32_t limit_value = additional_upper_limit()->GetInteger32Constant(); |
+ if (!additional_upper_limit_is_included()) { |
+ limit_value--; |
+ } |
+ if (limit_value < result) result = limit_value; |
+ } |
+ |
+ if (and_mask > 0 && and_mask < MAX_LIMIT) { |
+ if (and_mask < result) result = and_mask; |
+ return result; |
+ } |
+ |
+ // Add the effect of the or_mask. |
+ result |= or_mask; |
+ |
+ if (result >= MAX_LIMIT) { |
+ result = kNoLimit; |
+ } |
+ return result; |
+ } |
+ |
+ private: |
+ template <class T> void swap(T* a, T* b) { |
+ T c(*a); |
+ *a = *b; |
+ *b = c; |
+ } |
+ |
+ InductionVariableData(HPhi* phi, HValue* base, int32_t increment) |
+ : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment), |
+ limit_(NULL), limit_included_(false), limit_validity_(NULL), |
+ induction_exit_block_(NULL), induction_exit_target_(NULL), |
+ checks_(NULL), |
+ additional_upper_limit_(NULL), |
+ additional_upper_limit_is_included_(false), |
+ additional_lower_limit_(NULL), |
+ additional_lower_limit_is_included_(false) {} |
+ |
+ static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand); |
+ |
+ static HValue* IgnoreOsrValue(HValue* v); |
+ static InductionVariableData* GetInductionVariableData(HValue* v); |
+ |
+ HPhi* phi_; |
+ HValue* base_; |
+ int32_t increment_; |
+ HValue* limit_; |
+ bool limit_included_; |
+ HBasicBlock* limit_validity_; |
+ HBasicBlock* induction_exit_block_; |
+ HBasicBlock* induction_exit_target_; |
+ ChecksRelatedToLength* checks_; |
+ HValue* additional_upper_limit_; |
+ bool additional_upper_limit_is_included_; |
+ HValue* additional_lower_limit_; |
+ bool additional_lower_limit_is_included_; |
+}; |
+ |
+ |
class HPhi: public HValue { |
public: |
HPhi(int merged_index, Zone* zone) |
: inputs_(2, zone), |
merged_index_(merged_index), |
- phi_id_(-1) { |
+ phi_id_(-1), |
+ induction_variable_data_(NULL) { |
for (int i = 0; i < Representation::kNumRepresentations; i++) { |
non_phi_uses_[i] = 0; |
indirect_uses_[i] = 0; |
@@ -3086,6 +3354,21 @@ class HPhi: public HValue { |
int merged_index() const { return merged_index_; } |
+ InductionVariableData* induction_variable_data() { |
+ return induction_variable_data_; |
+ } |
+ bool IsInductionVariable() { |
+ return induction_variable_data_ != NULL; |
+ } |
+ bool IsLimitedInductionVariable() { |
+ return IsInductionVariable() && |
+ induction_variable_data_->limit() != NULL; |
+ } |
+ void DetectInductionVariable() { |
+ ASSERT(induction_variable_data_ == NULL); |
+ induction_variable_data_ = InductionVariableData::ExaminePhi(this); |
+ } |
+ |
virtual void AddInformativeDefinitions(); |
virtual void PrintTo(StringStream* stream); |
@@ -3153,6 +3436,7 @@ class HPhi: public HValue { |
int non_phi_uses_[Representation::kNumRepresentations]; |
int indirect_uses_[Representation::kNumRepresentations]; |
int phi_id_; |
+ InductionVariableData* induction_variable_data_; |
}; |
@@ -3660,15 +3944,16 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
HBoundsCheck(HValue* index, HValue* length) |
: skip_check_(false), |
base_(NULL), offset_(0), scale_(0), |
- responsibility_direction_(DIRECTION_NONE) { |
+ responsibility_direction_(DIRECTION_NONE), |
+ allow_equality_(false) { |
SetOperandAt(0, index); |
SetOperandAt(1, length); |
SetFlag(kFlexibleRepresentation); |
SetFlag(kUseGVN); |
} |
- bool skip_check() { return skip_check_; } |
- void set_skip_check(bool skip_check) { skip_check_ = skip_check; } |
+ bool skip_check() const { return skip_check_; } |
+ void set_skip_check() { skip_check_ = true; } |
HValue* base() { return base_; } |
int offset() { return offset_; } |
int scale() { return scale_; } |
@@ -3700,6 +3985,9 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
virtual Representation RequiredInputRepresentation(int arg_index) { |
return representation(); |
} |
+ virtual bool IsDeletable() const { |
+ return skip_check() && !FLAG_debug_code; |
+ } |
virtual bool IsRelationTrueInternal(NumericRelation relation, |
HValue* related_value, |
@@ -3711,6 +3999,8 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
HValue* index() { return OperandAt(0); } |
HValue* length() { return OperandAt(1); } |
+ bool allow_equality() { return allow_equality_; } |
+ void set_allow_equality(bool v) { allow_equality_ = v; } |
virtual int RedefinedOperandIndex() { return 0; } |
virtual bool IsPurelyInformativeDefinition() { return skip_check(); } |
@@ -3733,6 +4023,7 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
int offset_; |
int scale_; |
RangeGuaranteeDirection responsibility_direction_; |
+ bool allow_equality_; |
}; |
@@ -6608,7 +6899,6 @@ class HLoadFieldByIndex : public HTemplateInstruction<2> { |
virtual bool IsDeletable() const { return true; } |
}; |
- |
#undef DECLARE_INSTRUCTION |
#undef DECLARE_CONCRETE_INSTRUCTION |