Index: src/hydrogen-instructions.cc |
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc |
index fbc99e15453a5daf7223363fe59b8782e8543ed2..a8f197c5cf66d7f68696b52b06b8e6e4e44c16e4 100644 |
--- a/src/hydrogen-instructions.cc |
+++ b/src/hydrogen-instructions.cc |
@@ -86,9 +86,9 @@ void HValue::InferRepresentation(HInferRepresentationPhase* h_infer) { |
UpdateRepresentation(new_rep, h_infer, "inputs"); |
new_rep = RepresentationFromUses(); |
UpdateRepresentation(new_rep, h_infer, "uses"); |
- new_rep = RepresentationFromUseRequirements(); |
- if (new_rep.fits_into(Representation::Integer32())) { |
- UpdateRepresentation(new_rep, h_infer, "use requirements"); |
+ if (representation().IsSmi() && HasNonSmiUse()) { |
+ UpdateRepresentation( |
+ Representation::Integer32(), h_infer, "use requirements"); |
} |
} |
@@ -261,34 +261,56 @@ HValue* RangeEvaluationContext::ConvertGuarantee(HValue* guarantee) { |
} |
-static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { |
- if (result > kMaxInt) { |
- *overflow = true; |
- return kMaxInt; |
- } |
- if (result < kMinInt) { |
- *overflow = true; |
- return kMinInt; |
+static int32_t ConvertAndSetOverflow(Representation r, |
+ int64_t result, |
+ bool* overflow) { |
+ if (r.IsSmi()) { |
+ if (result > Smi::kMaxValue) { |
+ *overflow = true; |
+ return Smi::kMaxValue; |
+ } |
+ if (result < Smi::kMinValue) { |
+ *overflow = true; |
+ return Smi::kMinValue; |
+ } |
+ } else { |
+ if (result > kMaxInt) { |
+ *overflow = true; |
+ return kMaxInt; |
+ } |
+ if (result < kMinInt) { |
+ *overflow = true; |
+ return kMinInt; |
+ } |
} |
return static_cast<int32_t>(result); |
} |
-static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) { |
+static int32_t AddWithoutOverflow(Representation r, |
+ int32_t a, |
+ int32_t b, |
+ bool* overflow) { |
int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b); |
- return ConvertAndSetOverflow(result, overflow); |
+ return ConvertAndSetOverflow(r, result, overflow); |
} |
-static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) { |
+static int32_t SubWithoutOverflow(Representation r, |
+ int32_t a, |
+ int32_t b, |
+ bool* overflow) { |
int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b); |
- return ConvertAndSetOverflow(result, overflow); |
+ return ConvertAndSetOverflow(r, result, overflow); |
} |
-static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) { |
+static int32_t MulWithoutOverflow(const Representation& r, |
+ int32_t a, |
+ int32_t b, |
+ bool* overflow) { |
int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b); |
- return ConvertAndSetOverflow(result, overflow); |
+ return ConvertAndSetOverflow(r, result, overflow); |
} |
@@ -308,8 +330,9 @@ int32_t Range::Mask() const { |
void Range::AddConstant(int32_t value) { |
if (value == 0) return; |
bool may_overflow = false; // Overflow is ignored here. |
- lower_ = AddWithoutOverflow(lower_, value, &may_overflow); |
- upper_ = AddWithoutOverflow(upper_, value, &may_overflow); |
+ Representation r = Representation::Integer32(); |
+ lower_ = AddWithoutOverflow(r, lower_, value, &may_overflow); |
+ upper_ = AddWithoutOverflow(r, upper_, value, &may_overflow); |
#ifdef DEBUG |
Verify(); |
#endif |
@@ -368,10 +391,10 @@ void Range::Shl(int32_t value) { |
} |
-bool Range::AddAndCheckOverflow(Range* other) { |
+bool Range::AddAndCheckOverflow(const Representation& r, Range* other) { |
bool may_overflow = false; |
- lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow); |
- upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow); |
+ lower_ = AddWithoutOverflow(r, lower_, other->lower(), &may_overflow); |
+ upper_ = AddWithoutOverflow(r, upper_, other->upper(), &may_overflow); |
KeepOrder(); |
#ifdef DEBUG |
Verify(); |
@@ -380,10 +403,10 @@ bool Range::AddAndCheckOverflow(Range* other) { |
} |
-bool Range::SubAndCheckOverflow(Range* other) { |
+bool Range::SubAndCheckOverflow(const Representation& r, Range* other) { |
bool may_overflow = false; |
- lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow); |
- upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow); |
+ lower_ = SubWithoutOverflow(r, lower_, other->upper(), &may_overflow); |
+ upper_ = SubWithoutOverflow(r, upper_, other->lower(), &may_overflow); |
KeepOrder(); |
#ifdef DEBUG |
Verify(); |
@@ -408,12 +431,12 @@ void Range::Verify() const { |
#endif |
-bool Range::MulAndCheckOverflow(Range* other) { |
+bool Range::MulAndCheckOverflow(const Representation& r, Range* other) { |
bool may_overflow = false; |
- int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow); |
- int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow); |
- int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow); |
- int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow); |
+ int v1 = MulWithoutOverflow(r, lower_, other->lower(), &may_overflow); |
+ int v2 = MulWithoutOverflow(r, lower_, other->upper(), &may_overflow); |
+ int v3 = MulWithoutOverflow(r, upper_, other->lower(), &may_overflow); |
+ int v4 = MulWithoutOverflow(r, upper_, other->upper(), &may_overflow); |
lower_ = Min(Min(v1, v2), Min(v3, v4)); |
upper_ = Max(Max(v1, v2), Max(v3, v4)); |
#ifdef DEBUG |
@@ -1036,6 +1059,7 @@ void HBoundsCheck::TryGuaranteeRangeChanging(RangeEvaluationContext* context) { |
offset_ = context->offset(); |
SetResponsibilityForRange(DIRECTION_UPPER); |
context->set_upper_bound_guarantee(this); |
+ isolate()->counters()->bounds_checks_eliminated()->Increment(); |
} else if (context->upper_bound_guarantee() != NULL && |
context->upper_bound_guarantee() != this && |
context->upper_bound_guarantee()->block() != block() && |
@@ -1045,6 +1069,7 @@ void HBoundsCheck::TryGuaranteeRangeChanging(RangeEvaluationContext* context) { |
offset_ = context->offset(); |
SetResponsibilityForRange(DIRECTION_LOWER); |
context->set_lower_bound_guarantee(this); |
+ isolate()->counters()->bounds_checks_eliminated()->Increment(); |
} |
} |
@@ -1105,7 +1130,7 @@ void HBoundsCheck::AddInformativeDefinitions() { |
// is a hack. Move it to some other HPhase. |
if (FLAG_array_bounds_checks_elimination) { |
if (index()->TryGuaranteeRange(length())) { |
- set_skip_check(true); |
+ set_skip_check(); |
} |
if (DetectCompoundIndex()) { |
HBoundsCheckBaseIndexInformation* base_index_info = |
@@ -1431,7 +1456,7 @@ void HLoadFieldByIndex::PrintDataTo(StringStream* stream) { |
HValue* HBitwise::Canonicalize() { |
- if (!representation().IsInteger32()) return this; |
+ if (!representation().IsSmiOrInteger32()) return this; |
// If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x. |
int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0; |
if (left()->EqualsInteger32Constant(nop_constant) && |
@@ -1551,7 +1576,7 @@ HValue* HUnaryMathOperation::Canonicalize() { |
// If the input is integer32 then we replace the floor instruction |
// with its input. |
- if (val->representation().IsInteger32()) return val; |
+ if (val->representation().IsSmiOrInteger32()) return val; |
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_IA32) || \ |
defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_A64) |
@@ -1564,8 +1589,8 @@ HValue* HUnaryMathOperation::Canonicalize() { |
HValue* new_left = SimplifiedDividendForMathFloorOfDiv(left); |
if (new_left == NULL && |
hdiv->observed_input_representation(1).IsSmiOrInteger32()) { |
- new_left = new(block()->zone()) |
- HChange(left, Representation::Integer32(), false, false); |
+ new_left = new(block()->zone()) HChange( |
+ left, Representation::Integer32(), false, false, false); |
HChange::cast(new_left)->InsertBefore(this); |
} |
HValue* new_right = |
@@ -1575,8 +1600,8 @@ HValue* HUnaryMathOperation::Canonicalize() { |
CpuFeatures::IsSupported(SUDIV) && |
#endif |
hdiv->observed_input_representation(2).IsSmiOrInteger32()) { |
- new_right = new(block()->zone()) |
- HChange(right, Representation::Integer32(), false, false); |
+ new_right = new(block()->zone()) HChange( |
+ right, Representation::Integer32(), false, false, false); |
HChange::cast(new_right)->InsertBefore(this); |
} |
@@ -1686,7 +1711,7 @@ void HCheckMaps::PrintDataTo(StringStream* stream) { |
for (int i = 1; i < map_set()->length(); ++i) { |
stream->Add(",%p", *map_set()->at(i)); |
} |
- stream->Add("]"); |
+ stream->Add("]%s", CanOmitMapChecks() ? "(omitted)" : ""); |
} |
@@ -1747,7 +1772,7 @@ void HInstanceOf::PrintDataTo(StringStream* stream) { |
Range* HValue::InferRange(Zone* zone) { |
Range* result; |
- if (type().IsSmi()) { |
+ if (representation().IsSmi() || type().IsSmi()) { |
result = new(zone) Range(Smi::kMinValue, Smi::kMaxValue); |
result->set_can_be_minus_zero(false); |
} else { |
@@ -1762,10 +1787,11 @@ Range* HValue::InferRange(Zone* zone) { |
Range* HChange::InferRange(Zone* zone) { |
Range* input_range = value()->range(); |
- if (from().IsInteger32() && |
- to().IsSmiOrTagged() && |
- !value()->CheckFlag(HInstruction::kUint32) && |
- input_range != NULL && input_range->IsInSmiRange()) { |
+ if (from().IsInteger32() && !value()->CheckFlag(HInstruction::kUint32) && |
+ (to().IsSmi() || |
+ (to().IsTagged() && |
+ input_range != NULL && |
+ input_range->IsInSmiRange()))) { |
set_type(HType::Smi()); |
ClearGVNFlag(kChangesNewSpacePromotion); |
} |
@@ -1773,7 +1799,9 @@ Range* HChange::InferRange(Zone* zone) { |
? input_range->Copy(zone) |
: HValue::InferRange(zone); |
result->set_can_be_minus_zero(!to().IsSmiOrInteger32() || |
- !CheckFlag(kAllUsesTruncatingToInt32)); |
+ !(CheckFlag(kAllUsesTruncatingToInt32) || |
+ CheckFlag(kAllUsesTruncatingToSmi))); |
+ if (to().IsSmi()) result->ClampToSmi(); |
return result; |
} |
@@ -1810,15 +1838,18 @@ Range* HPhi::InferRange(Zone* zone) { |
Range* HAdd::InferRange(Zone* zone) { |
- if (representation().IsInteger32()) { |
+ Representation r = representation(); |
+ if (r.IsSmiOrInteger32()) { |
Range* a = left()->range(); |
Range* b = right()->range(); |
Range* res = a->Copy(zone); |
- if (!res->AddAndCheckOverflow(b) || |
- CheckFlag(kAllUsesTruncatingToInt32)) { |
+ if (!res->AddAndCheckOverflow(r, b) || |
+ (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || |
+ (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) { |
ClearFlag(kCanOverflow); |
} |
- res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && |
+ res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && |
+ !CheckFlag(kAllUsesTruncatingToInt32) && |
a->CanBeMinusZero() && b->CanBeMinusZero()); |
return res; |
} else { |
@@ -1828,15 +1859,18 @@ Range* HAdd::InferRange(Zone* zone) { |
Range* HSub::InferRange(Zone* zone) { |
- if (representation().IsInteger32()) { |
+ Representation r = representation(); |
+ if (r.IsSmiOrInteger32()) { |
Range* a = left()->range(); |
Range* b = right()->range(); |
Range* res = a->Copy(zone); |
- if (!res->SubAndCheckOverflow(b) || |
- CheckFlag(kAllUsesTruncatingToInt32)) { |
+ if (!res->SubAndCheckOverflow(r, b) || |
+ (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || |
+ (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) { |
ClearFlag(kCanOverflow); |
} |
- res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && |
+ res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && |
+ !CheckFlag(kAllUsesTruncatingToInt32) && |
a->CanBeMinusZero() && b->CanBeZero()); |
return res; |
} else { |
@@ -1846,17 +1880,19 @@ Range* HSub::InferRange(Zone* zone) { |
Range* HMul::InferRange(Zone* zone) { |
- if (representation().IsInteger32()) { |
+ Representation r = representation(); |
+ if (r.IsSmiOrInteger32()) { |
Range* a = left()->range(); |
Range* b = right()->range(); |
Range* res = a->Copy(zone); |
- if (!res->MulAndCheckOverflow(b)) { |
+ if (!res->MulAndCheckOverflow(r, b)) { |
// Clearing the kCanOverflow flag when kAllUsesAreTruncatingToInt32 |
// would be wrong, because truncated integer multiplication is too |
// precise and therefore not the same as converting to Double and back. |
ClearFlag(kCanOverflow); |
} |
- res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && |
+ res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && |
+ !CheckFlag(kAllUsesTruncatingToInt32) && |
((a->CanBeZero() && b->CanBeNegative()) || |
(a->CanBeNegative() && b->CanBeZero()))); |
return res; |
@@ -1974,8 +2010,452 @@ bool HPhi::IsRelationTrueInternal(NumericRelation relation, |
} |
+InductionVariableData* InductionVariableData::ExaminePhi(HPhi* phi) { |
+ if (phi->block()->loop_information() == NULL) return NULL; |
+ if (phi->OperandCount() != 2) return NULL; |
+ int32_t candidate_increment; |
+ |
+ candidate_increment = ComputeIncrement(phi, phi->OperandAt(0)); |
+ if (candidate_increment != 0) { |
+ return new(phi->block()->graph()->zone()) |
+ InductionVariableData(phi, phi->OperandAt(1), candidate_increment); |
+ } |
+ |
+ candidate_increment = ComputeIncrement(phi, phi->OperandAt(1)); |
+ if (candidate_increment != 0) { |
+ return new(phi->block()->graph()->zone()) |
+ InductionVariableData(phi, phi->OperandAt(0), candidate_increment); |
+ } |
+ |
+ return NULL; |
+} |
+ |
+ |
+/* |
+ * This function tries to match the following patterns (and all the relevant |
+ * variants related to |, & and + being commutative): |
+ * base | constant_or_mask |
+ * base & constant_and_mask |
+ * (base + constant_offset) & constant_and_mask |
+ * (base - constant_offset) & constant_and_mask |
+ */ |
+void InductionVariableData::DecomposeBitwise( |
+ HValue* value, |
+ BitwiseDecompositionResult* result) { |
+ HValue* base = IgnoreOsrValue(value); |
+ result->base = value; |
+ |
+ if (!base->representation().IsInteger32()) return; |
+ |
+ if (base->IsBitwise()) { |
+ bool allow_offset = false; |
+ int32_t mask = 0; |
+ |
+ HBitwise* bitwise = HBitwise::cast(base); |
+ if (bitwise->right()->IsInteger32Constant()) { |
+ mask = bitwise->right()->GetInteger32Constant(); |
+ base = bitwise->left(); |
+ } else if (bitwise->left()->IsInteger32Constant()) { |
+ mask = bitwise->left()->GetInteger32Constant(); |
+ base = bitwise->right(); |
+ } else { |
+ return; |
+ } |
+ if (bitwise->op() == Token::BIT_AND) { |
+ result->and_mask = mask; |
+ allow_offset = true; |
+ } else if (bitwise->op() == Token::BIT_OR) { |
+ result->or_mask = mask; |
+ } else { |
+ return; |
+ } |
+ |
+ result->context = bitwise->context(); |
+ |
+ if (allow_offset) { |
+ if (base->IsAdd()) { |
+ HAdd* add = HAdd::cast(base); |
+ if (add->right()->IsInteger32Constant()) { |
+ base = add->left(); |
+ } else if (add->left()->IsInteger32Constant()) { |
+ base = add->right(); |
+ } |
+ } else if (base->IsSub()) { |
+ HSub* sub = HSub::cast(base); |
+ if (sub->right()->IsInteger32Constant()) { |
+ base = sub->left(); |
+ } |
+ } |
+ } |
+ |
+ result->base = base; |
+ } |
+} |
+ |
+ |
+void InductionVariableData::AddCheck(HBoundsCheck* check, |
+ int32_t upper_limit) { |
+ ASSERT(limit_validity() != NULL); |
+ if (limit_validity() != check->block() && |
+ !limit_validity()->Dominates(check->block())) return; |
+ if (!phi()->block()->current_loop()->IsNestedInThisLoop( |
+ check->block()->current_loop())) return; |
+ |
+ ChecksRelatedToLength* length_checks = checks(); |
+ while (length_checks != NULL) { |
+ if (length_checks->length() == check->length()) break; |
+ length_checks = length_checks->next(); |
+ } |
+ if (length_checks == NULL) { |
+ length_checks = new(check->block()->zone()) |
+ ChecksRelatedToLength(check->length(), checks()); |
+ checks_ = length_checks; |
+ } |
+ |
+ length_checks->AddCheck(check, upper_limit); |
+} |
+ |
+ |
+void InductionVariableData::ChecksRelatedToLength::CloseCurrentBlock() { |
+ if (checks() != NULL) { |
+ InductionVariableCheck* c = checks(); |
+ HBasicBlock* current_block = c->check()->block(); |
+ while (c != NULL && c->check()->block() == current_block) { |
+ c->set_upper_limit(current_upper_limit_); |
+ c = c->next(); |
+ } |
+ } |
+} |
+ |
+ |
+void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock( |
+ Token::Value token, |
+ int32_t mask, |
+ HValue* index_base, |
+ HValue* context) { |
+ ASSERT(first_check_in_block() != NULL); |
+ HValue* previous_index = first_check_in_block()->index(); |
+ ASSERT(context != NULL); |
+ |
+ set_added_constant(new(index_base->block()->graph()->zone()) HConstant( |
+ mask, index_base->representation())); |
+ if (added_index() != NULL) { |
+ added_constant()->InsertBefore(added_index()); |
+ } else { |
+ added_constant()->InsertBefore(first_check_in_block()); |
+ } |
+ |
+ if (added_index() == NULL) { |
+ first_check_in_block()->ReplaceAllUsesWith(first_check_in_block()->index()); |
+ HInstruction* new_index = HBitwise::New( |
+ index_base->block()->graph()->zone(), |
+ token, context, index_base, added_constant()); |
+ ASSERT(new_index->IsBitwise()); |
+ new_index->ClearAllSideEffects(); |
+ new_index->AssumeRepresentation(Representation::Integer32()); |
+ set_added_index(HBitwise::cast(new_index)); |
+ added_index()->InsertBefore(first_check_in_block()); |
+ } |
+ ASSERT(added_index()->op() == token); |
+ |
+ added_index()->SetOperandAt(1, index_base); |
+ added_index()->SetOperandAt(2, added_constant()); |
+ first_check_in_block()->SetOperandAt(0, added_index()); |
+ if (previous_index->UseCount() == 0) { |
+ previous_index->DeleteAndReplaceWith(NULL); |
+ } |
+} |
+ |
+void InductionVariableData::ChecksRelatedToLength::AddCheck( |
+ HBoundsCheck* check, |
+ int32_t upper_limit) { |
+ BitwiseDecompositionResult decomposition; |
+ InductionVariableData::DecomposeBitwise(check->index(), &decomposition); |
+ |
+ if (first_check_in_block() == NULL || |
+ first_check_in_block()->block() != check->block()) { |
+ CloseCurrentBlock(); |
+ |
+ first_check_in_block_ = check; |
+ set_added_index(NULL); |
+ set_added_constant(NULL); |
+ current_and_mask_in_block_ = decomposition.and_mask; |
+ current_or_mask_in_block_ = decomposition.or_mask; |
+ current_upper_limit_ = upper_limit; |
+ |
+ InductionVariableCheck* new_check = new(check->block()->graph()->zone()) |
+ InductionVariableCheck(check, checks_, upper_limit); |
+ checks_ = new_check; |
+ return; |
+ } |
+ |
+ if (upper_limit > current_upper_limit()) { |
+ current_upper_limit_ = upper_limit; |
+ } |
+ |
+ if (decomposition.and_mask != 0 && |
+ current_or_mask_in_block() == 0) { |
+ if (current_and_mask_in_block() == 0 || |
+ decomposition.and_mask > current_and_mask_in_block()) { |
+ UseNewIndexInCurrentBlock(Token::BIT_AND, |
+ decomposition.and_mask, |
+ decomposition.base, |
+ decomposition.context); |
+ current_and_mask_in_block_ = decomposition.and_mask; |
+ } |
+ check->set_skip_check(); |
+ } |
+ if (current_and_mask_in_block() == 0) { |
+ if (decomposition.or_mask > current_or_mask_in_block()) { |
+ UseNewIndexInCurrentBlock(Token::BIT_OR, |
+ decomposition.or_mask, |
+ decomposition.base, |
+ decomposition.context); |
+ current_or_mask_in_block_ = decomposition.or_mask; |
+ } |
+ check->set_skip_check(); |
+ } |
+ |
+ if (!check->skip_check()) { |
+ InductionVariableCheck* new_check = new(check->block()->graph()->zone()) |
+ InductionVariableCheck(check, checks_, upper_limit); |
+ checks_ = new_check; |
+ } |
+} |
+ |
+ |
+/* |
+ * This method detects if phi is an induction variable, with phi_operand as |
+ * its "incremented" value (the other operand would be the "base" value). |
+ * |
+ * It cheks is phi_operand has the form "phi + constant". |
+ * If yes, the constant is the increment that the induction variable gets at |
+ * every loop iteration. |
+ * Otherwise it returns 0. |
+ */ |
+int32_t InductionVariableData::ComputeIncrement(HPhi* phi, |
+ HValue* phi_operand) { |
+ if (!phi_operand->representation().IsInteger32()) return 0; |
+ |
+ if (phi_operand->IsAdd()) { |
+ HAdd* operation = HAdd::cast(phi_operand); |
+ if (operation->left() == phi && |
+ operation->right()->IsInteger32Constant()) { |
+ return operation->right()->GetInteger32Constant(); |
+ } else if (operation->right() == phi && |
+ operation->left()->IsInteger32Constant()) { |
+ return operation->left()->GetInteger32Constant(); |
+ } |
+ } else if (phi_operand->IsSub()) { |
+ HSub* operation = HSub::cast(phi_operand); |
+ if (operation->left() == phi && |
+ operation->right()->IsInteger32Constant()) { |
+ return -operation->right()->GetInteger32Constant(); |
+ } |
+ } |
+ |
+ return 0; |
+} |
+ |
+ |
+/* |
+ * Swaps the information in "update" with the one contained in "this". |
+ * The swapping is important because this method is used while doing a |
+ * dominator tree traversal, and "update" will retain the old data that |
+ * will be restored while backtracking. |
+ */ |
+void InductionVariableData::UpdateAdditionalLimit( |
+ InductionVariableLimitUpdate* update) { |
+ 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); |
+ } |
+} |
+ |
+ |
+int32_t InductionVariableData::ComputeUpperLimit(int32_t and_mask, |
+ int32_t or_mask) { |
+ // 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; |
+ |
+ return result >= MAX_LIMIT ? kNoLimit : result; |
+} |
+ |
+ |
+HValue* InductionVariableData::IgnoreOsrValue(HValue* v) { |
+ if (!v->IsPhi()) return v; |
+ HPhi* phi = HPhi::cast(v); |
+ if (phi->OperandCount() != 2) return v; |
+ if (phi->OperandAt(0)->block()->is_osr_entry()) { |
+ return phi->OperandAt(1); |
+ } else if (phi->OperandAt(1)->block()->is_osr_entry()) { |
+ return phi->OperandAt(0); |
+ } else { |
+ return v; |
+ } |
+} |
+ |
+ |
+InductionVariableData* InductionVariableData::GetInductionVariableData( |
+ HValue* v) { |
+ v = IgnoreOsrValue(v); |
+ if (v->IsPhi()) { |
+ return HPhi::cast(v)->induction_variable_data(); |
+ } |
+ return NULL; |
+} |
+ |
+ |
+/* |
+ * Check if a conditional branch to "current_branch" with token "token" is |
+ * the branch that keeps the induction loop running (and, conversely, will |
+ * terminate it if the "other_branch" is taken). |
+ * |
+ * Three conditions must be met: |
+ * - "current_branch" must be in the induction loop. |
+ * - "other_branch" must be out of the induction loop. |
+ * - "token" and the induction increment must be "compatible": the token should |
+ * be a condition that keeps the execution inside the loop until the limit is |
+ * reached. |
+ */ |
+bool InductionVariableData::CheckIfBranchIsLoopGuard( |
+ Token::Value token, |
+ HBasicBlock* current_branch, |
+ HBasicBlock* other_branch) { |
+ if (!phi()->block()->current_loop()->IsNestedInThisLoop( |
+ current_branch->current_loop())) { |
+ return false; |
+ } |
+ |
+ if (phi()->block()->current_loop()->IsNestedInThisLoop( |
+ other_branch->current_loop())) { |
+ return false; |
+ } |
+ |
+ if (increment() > 0 && (token == Token::LT || token == Token::LTE)) { |
+ return true; |
+ } |
+ if (increment() < 0 && (token == Token::GT || token == Token::GTE)) { |
+ return true; |
+ } |
+ if (Token::IsInequalityOp(token) && (increment() == 1 || increment() == -1)) { |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+ |
+void InductionVariableData::ComputeLimitFromPredecessorBlock( |
+ HBasicBlock* block, |
+ LimitFromPredecessorBlock* result) { |
+ if (block->predecessors()->length() != 1) return; |
+ HBasicBlock* predecessor = block->predecessors()->at(0); |
+ HInstruction* end = predecessor->last(); |
+ |
+ if (!end->IsCompareNumericAndBranch()) return; |
+ HCompareNumericAndBranch* branch = HCompareNumericAndBranch::cast(end); |
+ |
+ Token::Value token = branch->token(); |
+ if (!Token::IsArithmeticCompareOp(token)) return; |
+ |
+ HBasicBlock* other_target; |
+ if (block == branch->SuccessorAt(0)) { |
+ other_target = branch->SuccessorAt(1); |
+ } else { |
+ other_target = branch->SuccessorAt(0); |
+ token = Token::NegateCompareOp(token); |
+ ASSERT(block == branch->SuccessorAt(1)); |
+ } |
+ |
+ InductionVariableData* data; |
+ |
+ data = GetInductionVariableData(branch->left()); |
+ HValue* limit = branch->right(); |
+ if (data == NULL) { |
+ data = GetInductionVariableData(branch->right()); |
+ token = Token::ReverseCompareOp(token); |
+ limit = branch->left(); |
+ } |
+ |
+ if (data != NULL) { |
+ result->variable = data; |
+ result->token = token; |
+ result->limit = limit; |
+ result->other_target = other_target; |
+ } |
+} |
+ |
+ |
+/* |
+ * Compute the limit that is imposed on an induction variable when entering |
+ * "block" (if any). |
+ * If the limit is the "proper" induction limit (the one that makes the loop |
+ * terminate when the induction variable reaches it) it is stored directly in |
+ * the induction variable data. |
+ * Otherwise the limit is written in "additional_limit" and the method |
+ * returns true. |
+ */ |
+bool InductionVariableData::ComputeInductionVariableLimit( |
+ HBasicBlock* block, |
+ InductionVariableLimitUpdate* additional_limit) { |
+ LimitFromPredecessorBlock limit; |
+ ComputeLimitFromPredecessorBlock(block, &limit); |
+ if (!limit.LimitIsValid()) return false; |
+ |
+ if (limit.variable->CheckIfBranchIsLoopGuard(limit.token, |
+ block, |
+ limit.other_target)) { |
+ limit.variable->limit_ = limit.limit; |
+ limit.variable->limit_included_ = limit.LimitIsIncluded(); |
+ limit.variable->limit_validity_ = block; |
+ limit.variable->induction_exit_block_ = block->predecessors()->at(0); |
+ limit.variable->induction_exit_target_ = limit.other_target; |
+ return false; |
+ } else { |
+ additional_limit->updated_variable = limit.variable; |
+ additional_limit->limit = limit.limit; |
+ additional_limit->limit_is_upper = limit.LimitIsUpper(); |
+ additional_limit->limit_is_included = limit.LimitIsIncluded(); |
+ return true; |
+ } |
+} |
+ |
+ |
Range* HMathMinMax::InferRange(Zone* zone) { |
- if (representation().IsInteger32()) { |
+ if (representation().IsSmiOrInteger32()) { |
Range* a = left()->range(); |
Range* b = right()->range(); |
Range* res = a->Copy(zone); |
@@ -2060,6 +2540,7 @@ void HPhi::InitRealUses(int phi_id) { |
// Compute a conservative approximation of truncating uses before inferring |
// representations. The proper, exact computation will be done later, when |
// inserting representation changes. |
+ SetFlag(kTruncatingToSmi); |
SetFlag(kTruncatingToInt32); |
for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
HValue* value = it.value(); |
@@ -2070,8 +2551,13 @@ void HPhi::InitRealUses(int phi_id) { |
PrintF("#%d Phi is used by real #%d %s as %s\n", |
id(), value->id(), value->Mnemonic(), rep.Mnemonic()); |
} |
- if (!value->IsSimulate() && !value->CheckFlag(kTruncatingToInt32)) { |
- ClearFlag(kTruncatingToInt32); |
+ if (!value->IsSimulate()) { |
+ if (!value->CheckFlag(kTruncatingToSmi)) { |
+ ClearFlag(kTruncatingToSmi); |
+ } |
+ if (!value->CheckFlag(kTruncatingToInt32)) { |
+ ClearFlag(kTruncatingToInt32); |
+ } |
} |
} |
} |
@@ -2142,16 +2628,6 @@ void HSimulate::PrintDataTo(StringStream* stream) { |
} |
-void HDeoptimize::PrintDataTo(StringStream* stream) { |
- if (OperandCount() == 0) return; |
- OperandAt(0)->PrintNameTo(stream); |
- for (int i = 1; i < OperandCount(); ++i) { |
- stream->Add(" "); |
- OperandAt(i)->PrintNameTo(stream); |
- } |
-} |
- |
- |
void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target, |
Zone* zone) { |
ASSERT(return_target->IsInlineReturnTarget()); |
@@ -2268,7 +2744,7 @@ HConstant::HConstant(double double_value, |
void HConstant::Initialize(Representation r) { |
if (r.IsNone()) { |
- if (has_smi_value_) { |
+ if (has_smi_value_ && kSmiValueSize == 31) { |
r = Representation::Smi(); |
} else if (has_int32_value_) { |
r = Representation::Integer32(); |
@@ -2316,20 +2792,38 @@ HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const { |
} |
-HConstant* HConstant::CopyToTruncatedInt32(Zone* zone) const { |
+Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) { |
+ HConstant* res = NULL; |
if (has_int32_value_) { |
- return new(zone) HConstant(int32_value_, |
- Representation::Integer32(), |
- is_not_in_new_space_, |
- handle_); |
+ res = new(zone) HConstant(int32_value_, |
+ Representation::Integer32(), |
+ is_not_in_new_space_, |
+ handle_); |
+ } else if (has_double_value_) { |
+ res = new(zone) HConstant(DoubleToInt32(double_value_), |
+ Representation::Integer32(), |
+ is_not_in_new_space_, |
+ handle_); |
+ } else { |
+ ASSERT(!HasNumberValue()); |
+ Maybe<HConstant*> number = CopyToTruncatedNumber(zone); |
+ if (number.has_value) return number.value->CopyToTruncatedInt32(zone); |
} |
- if (has_double_value_) { |
- return new(zone) HConstant(DoubleToInt32(double_value_), |
- Representation::Integer32(), |
- is_not_in_new_space_, |
- handle_); |
+ return Maybe<HConstant*>(res != NULL, res); |
+} |
+ |
+ |
+Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Zone* zone) { |
+ HConstant* res = NULL; |
+ if (handle()->IsBoolean()) { |
+ res = handle()->BooleanValue() ? |
+ new(zone) HConstant(1) : new(zone) HConstant(0); |
+ } else if (handle()->IsUndefined()) { |
+ res = new(zone) HConstant(OS::nan_value()); |
+ } else if (handle()->IsNull()) { |
+ res = new(zone) HConstant(0); |
} |
- return NULL; |
+ return Maybe<HConstant*>(res != NULL, res); |
} |
@@ -2357,25 +2851,18 @@ void HBinaryOperation::InferRepresentation(HInferRepresentationPhase* h_infer) { |
ASSERT(CheckFlag(kFlexibleRepresentation)); |
Representation new_rep = RepresentationFromInputs(); |
UpdateRepresentation(new_rep, h_infer, "inputs"); |
- // When the operation has information about its own output type, don't look |
- // at uses. |
- if (!observed_output_representation_.IsNone()) return; |
- new_rep = RepresentationFromUses(); |
- UpdateRepresentation(new_rep, h_infer, "uses"); |
- new_rep = RepresentationFromUseRequirements(); |
- if (new_rep.fits_into(Representation::Integer32())) { |
- UpdateRepresentation(new_rep, h_infer, "use requirements"); |
+ if (observed_output_representation_.IsNone()) { |
+ new_rep = RepresentationFromUses(); |
+ UpdateRepresentation(new_rep, h_infer, "uses"); |
+ } else { |
+ new_rep = RepresentationFromOutput(); |
+ UpdateRepresentation(new_rep, h_infer, "output"); |
} |
-} |
- |
-bool HBinaryOperation::IgnoreObservedOutputRepresentation( |
- Representation current_rep) { |
- return observed_output_representation_.IsDouble() && |
- current_rep.IsInteger32() && |
- // Mul in Integer32 mode would be too precise. |
- !this->IsMul() && |
- CheckUsesForFlag(kTruncatingToInt32); |
+ if (representation().IsSmi() && HasNonSmiUse()) { |
+ UpdateRepresentation( |
+ Representation::Integer32(), h_infer, "use requirements"); |
+ } |
} |
@@ -2384,28 +2871,38 @@ Representation HBinaryOperation::RepresentationFromInputs() { |
// the currently assumed output representation. |
Representation rep = representation(); |
for (int i = 1; i <= 2; ++i) { |
- Representation input_rep = observed_input_representation(i); |
- if (input_rep.is_more_general_than(rep)) rep = input_rep; |
+ rep = rep.generalize(observed_input_representation(i)); |
} |
// If any of the actual input representation is more general than what we |
// have so far but not Tagged, use that representation instead. |
Representation left_rep = left()->representation(); |
Representation right_rep = right()->representation(); |
+ if (!left_rep.IsTagged()) rep = rep.generalize(left_rep); |
+ if (!right_rep.IsTagged()) rep = rep.generalize(right_rep); |
- if (left_rep.is_more_general_than(rep) && !left_rep.IsTagged()) { |
- rep = left_rep; |
- } |
- if (right_rep.is_more_general_than(rep) && !right_rep.IsTagged()) { |
- rep = right_rep; |
- } |
+ return rep; |
+} |
+ |
+ |
+bool HBinaryOperation::IgnoreObservedOutputRepresentation( |
+ Representation current_rep) { |
+ return ((current_rep.IsInteger32() && CheckUsesForFlag(kTruncatingToInt32)) || |
+ (current_rep.IsSmi() && CheckUsesForFlag(kTruncatingToSmi))) && |
+ // Mul in Integer32 mode would be too precise. |
+ !this->IsMul(); |
+} |
+ |
+ |
+Representation HBinaryOperation::RepresentationFromOutput() { |
+ Representation rep = representation(); |
// Consider observed output representation, but ignore it if it's Double, |
// this instruction is not a division, and all its uses are truncating |
// to Integer32. |
if (observed_output_representation_.is_more_general_than(rep) && |
!IgnoreObservedOutputRepresentation(rep)) { |
- rep = observed_output_representation_; |
+ return observed_output_representation_; |
} |
- return rep; |
+ return Representation::None(); |
} |
@@ -2721,7 +3218,7 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, |
types_.Add(types->at(i), zone); |
break; |
} |
- case CONSTANT_FUNCTION: |
+ case CONSTANT: |
types_.Add(types->at(i), zone); |
break; |
case CALLBACKS: |
@@ -2763,6 +3260,55 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, |
} |
+HCheckMaps* HCheckMaps::New(HValue* value, |
+ Handle<Map> map, |
+ Zone* zone, |
+ CompilationInfo* info, |
+ HValue* typecheck) { |
+ HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); |
+ check_map->map_set_.Add(map, zone); |
+ if (map->CanOmitMapChecks() && |
+ value->IsConstant() && |
+ HConstant::cast(value)->InstanceOf(map)) { |
+ check_map->omit(info); |
+ } |
+ return check_map; |
+} |
+ |
+ |
+HCheckMaps* HCheckMaps::NewWithTransitions(HValue* value, |
+ Handle<Map> map, |
+ Zone* zone, |
+ CompilationInfo* info) { |
+ HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, value); |
+ check_map->map_set_.Add(map, zone); |
+ |
+ // Since transitioned elements maps of the initial map don't fail the map |
+ // check, the CheckMaps instruction doesn't need to depend on ElementsKinds. |
+ check_map->ClearGVNFlag(kDependsOnElementsKind); |
+ |
+ ElementsKind kind = map->elements_kind(); |
+ bool packed = IsFastPackedElementsKind(kind); |
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) { |
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed); |
+ Map* transitioned_map = |
+ map->LookupElementsTransitionMap(kind); |
+ if (transitioned_map) { |
+ check_map->map_set_.Add(Handle<Map>(transitioned_map), zone); |
+ } |
+ }; |
+ |
+ if (map->CanOmitMapChecks() && |
+ value->IsConstant() && |
+ HConstant::cast(value)->InstanceOf(map)) { |
+ check_map->omit(info); |
+ } |
+ |
+ check_map->map_set_.Sort(); |
+ return check_map; |
+} |
+ |
+ |
void HCheckMaps::FinalizeUniqueValueId() { |
if (!map_unique_ids_.is_empty()) return; |
Zone* zone = block()->zone(); |
@@ -3193,11 +3739,6 @@ HType HStringCharFromCode::CalculateInferredType() { |
} |
-HType HAllocate::CalculateInferredType() { |
- return type_; |
-} |
- |
- |
void HAllocate::HandleSideEffectDominator(GVNFlag side_effect, |
HValue* dominator) { |
ASSERT(side_effect == kChangesNewSpacePromotion); |
@@ -3216,12 +3757,9 @@ void HAllocate::HandleSideEffectDominator(GVNFlag side_effect, |
HValue* dominator_size = dominator_allocate_instr->size(); |
HValue* current_size = size(); |
// We can just fold allocations that are guaranteed in new space. |
- // TODO(hpayer): Support double aligned allocations. |
// TODO(hpayer): Add support for non-constant allocation in dominator. |
- if (!GuaranteedInNewSpace() || MustAllocateDoubleAligned() || |
- !current_size->IsInteger32Constant() || |
+ if (!GuaranteedInNewSpace() || !current_size->IsInteger32Constant() || |
!dominator_allocate_instr->GuaranteedInNewSpace() || |
- dominator_allocate_instr->MustAllocateDoubleAligned() || |
!dominator_size->IsInteger32Constant()) { |
if (FLAG_trace_allocation_folding) { |
PrintF("#%d (%s) cannot fold into #%d (%s)\n", |
@@ -3236,6 +3774,17 @@ void HAllocate::HandleSideEffectDominator(GVNFlag side_effect, |
int32_t current_size_constant = |
HConstant::cast(current_size)->GetInteger32Constant(); |
int32_t new_dominator_size = dominator_size_constant + current_size_constant; |
+ |
+ if (MustAllocateDoubleAligned()) { |
+ if (!dominator_allocate_instr->MustAllocateDoubleAligned()) { |
+ dominator_allocate_instr->SetFlags(HAllocate::ALLOCATE_DOUBLE_ALIGNED); |
+ } |
+ if ((dominator_size_constant & kDoubleAlignmentMask) != 0) { |
+ dominator_size_constant += kDoubleSize / 2; |
+ new_dominator_size += kDoubleSize / 2; |
+ } |
+ } |
+ |
if (new_dominator_size > Page::kMaxNonCodeHeapObjectSize) { |
if (FLAG_trace_allocation_folding) { |
PrintF("#%d (%s) cannot fold into #%d (%s) due to size: %d\n", |
@@ -3290,29 +3839,28 @@ HType HFunctionLiteral::CalculateInferredType() { |
HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero( |
BitVector* visited) { |
visited->Add(id()); |
- if (representation().IsInteger32() && |
- !value()->representation().IsInteger32()) { |
+ if (representation().IsSmiOrInteger32() && |
+ !value()->representation().Equals(representation())) { |
if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { |
SetFlag(kBailoutOnMinusZero); |
} |
} |
- if (RequiredInputRepresentation(0).IsInteger32() && |
- representation().IsInteger32()) { |
+ if (RequiredInputRepresentation(0).IsSmiOrInteger32() && |
+ representation().Equals(RequiredInputRepresentation(0))) { |
return value(); |
} |
return NULL; |
} |
- |
HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
visited->Add(id()); |
- if (from().IsInteger32()) return NULL; |
+ if (from().IsSmiOrInteger32()) return NULL; |
if (CanTruncateToInt32()) return NULL; |
if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { |
SetFlag(kBailoutOnMinusZero); |
} |
- ASSERT(!from().IsInteger32() || !to().IsInteger32()); |
+ ASSERT(!from().IsSmiOrInteger32() || !to().IsSmiOrInteger32()); |
return NULL; |
} |
@@ -3399,7 +3947,7 @@ bool HStoreKeyed::NeedsCanonicalization() { |
} |
if (value()->IsChange()) { |
- if (HChange::cast(value())->from().IsInteger32()) { |
+ if (HChange::cast(value())->from().IsSmiOrInteger32()) { |
return false; |
} |
if (HChange::cast(value())->value()->type().IsSmi()) { |
@@ -3410,8 +3958,8 @@ bool HStoreKeyed::NeedsCanonicalization() { |
} |
-#define H_CONSTANT_INT32(val) \ |
-new(zone) HConstant(static_cast<int32_t>(val), Representation::Integer32()) |
+#define H_CONSTANT_INT(val) \ |
+new(zone) HConstant(static_cast<int32_t>(val)) |
#define H_CONSTANT_DOUBLE(val) \ |
new(zone) HConstant(static_cast<double>(val), Representation::Double()) |
@@ -3424,7 +3972,7 @@ HInstruction* HInstr::New( \ |
if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ |
double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \ |
if (TypeInfo::IsInt32Double(double_res)) { \ |
- return H_CONSTANT_INT32(double_res); \ |
+ return H_CONSTANT_INT(double_res); \ |
} \ |
return H_CONSTANT_DOUBLE(double_res); \ |
} \ |
@@ -3623,7 +4171,7 @@ HInstruction* HMod::New(Zone* zone, |
if ((res == 0) && (dividend < 0)) { |
return H_CONSTANT_DOUBLE(-0.0); |
} |
- return H_CONSTANT_INT32(res); |
+ return H_CONSTANT_INT(res); |
} |
} |
} |
@@ -3641,7 +4189,7 @@ HInstruction* HDiv::New( |
if (c_right->DoubleValue() != 0) { |
double double_res = c_left->DoubleValue() / c_right->DoubleValue(); |
if (TypeInfo::IsInt32Double(double_res)) { |
- return H_CONSTANT_INT32(double_res); |
+ return H_CONSTANT_INT(double_res); |
} |
return H_CONSTANT_DOUBLE(double_res); |
} else { |
@@ -3678,7 +4226,7 @@ HInstruction* HBitwise::New( |
result = 0; // Please the compiler. |
UNREACHABLE(); |
} |
- return H_CONSTANT_INT32(result); |
+ return H_CONSTANT_INT(result); |
} |
} |
return new(zone) HBitwise(op, context, left, right); |
@@ -3692,7 +4240,7 @@ HInstruction* HInstr::New( \ |
HConstant* c_left = HConstant::cast(left); \ |
HConstant* c_right = HConstant::cast(right); \ |
if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ |
- return H_CONSTANT_INT32(result); \ |
+ return H_CONSTANT_INT(result); \ |
} \ |
} \ |
return new(zone) HInstr(context, left, right); \ |
@@ -3718,14 +4266,14 @@ HInstruction* HShr::New( |
if ((right_val == 0) && (left_val < 0)) { |
return H_CONSTANT_DOUBLE(static_cast<uint32_t>(left_val)); |
} |
- return H_CONSTANT_INT32(static_cast<uint32_t>(left_val) >> right_val); |
+ return H_CONSTANT_INT(static_cast<uint32_t>(left_val) >> right_val); |
} |
} |
return new(zone) HShr(context, left, right); |
} |
-#undef H_CONSTANT_INT32 |
+#undef H_CONSTANT_INT |
#undef H_CONSTANT_DOUBLE |
@@ -3750,8 +4298,7 @@ void HPhi::SimplifyConstantInputs() { |
continue; |
} else if (operand->HasDoubleValue()) { |
HConstant* integer_input = |
- new(graph->zone()) HConstant(DoubleToInt32(operand->DoubleValue()), |
- Representation::Integer32()); |
+ new(graph->zone()) HConstant(DoubleToInt32(operand->DoubleValue())); |
integer_input->InsertAfter(operand); |
SetOperandAt(i, integer_input); |
} else if (operand == graph->GetConstantTrue()) { |
@@ -3766,7 +4313,7 @@ void HPhi::SimplifyConstantInputs() { |
HValue* use = it.value(); |
if (use->IsBinaryOperation()) { |
HBinaryOperation::cast(use)->set_observed_input_representation( |
- it.index(), Representation::Integer32()); |
+ it.index(), Representation::Smi()); |
} |
} |
} |
@@ -3815,6 +4362,17 @@ Representation HValue::RepresentationFromUseRequirements() { |
} |
+bool HValue::HasNonSmiUse() { |
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
+ // We check for observed_input_representation elsewhere. |
+ Representation use_rep = |
+ it.value()->RequiredInputRepresentation(it.index()); |
+ if (!use_rep.IsNone() && !use_rep.IsSmi()) return true; |
+ } |
+ return false; |
+} |
+ |
+ |
// Node-specific verification code is only included in debug mode. |
#ifdef DEBUG |
@@ -3858,7 +4416,8 @@ HObjectAccess HObjectAccess::ForFixedArrayHeader(int offset) { |
} |
-HObjectAccess HObjectAccess::ForJSObjectOffset(int offset) { |
+HObjectAccess HObjectAccess::ForJSObjectOffset(int offset, |
+ Representation representation) { |
ASSERT(offset >= 0); |
Portion portion = kInobject; |
@@ -3867,7 +4426,7 @@ HObjectAccess HObjectAccess::ForJSObjectOffset(int offset) { |
} else if (offset == JSObject::kMapOffset) { |
portion = kMaps; |
} |
- return HObjectAccess(portion, offset, Handle<String>::null()); |
+ return HObjectAccess(portion, offset, representation); |
} |
@@ -3882,13 +4441,14 @@ HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) { |
} else if (offset == JSObject::kMapOffset) { |
portion = kMaps; |
} |
- return HObjectAccess(portion, offset, Handle<String>::null()); |
+ return HObjectAccess(portion, offset); |
} |
-HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset) { |
+HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset, |
+ Representation representation) { |
ASSERT(offset >= 0); |
- return HObjectAccess(kBackingStore, offset, Handle<String>::null()); |
+ return HObjectAccess(kBackingStore, offset, representation); |
} |
@@ -3896,30 +4456,35 @@ HObjectAccess HObjectAccess::ForField(Handle<Map> map, |
LookupResult *lookup, Handle<String> name) { |
ASSERT(lookup->IsField() || lookup->IsTransitionToField(*map)); |
int index; |
+ Representation representation; |
if (lookup->IsField()) { |
index = lookup->GetLocalFieldIndexFromMap(*map); |
+ representation = lookup->representation(); |
} else { |
Map* transition = lookup->GetTransitionMapFromMap(*map); |
int descriptor = transition->LastAdded(); |
index = transition->instance_descriptors()->GetFieldIndex(descriptor) - |
map->inobject_properties(); |
+ PropertyDetails details = |
+ transition->instance_descriptors()->GetDetails(descriptor); |
+ representation = details.representation(); |
} |
if (index < 0) { |
// Negative property indices are in-object properties, indexed |
// from the end of the fixed part of the object. |
int offset = (index * kPointerSize) + map->instance_size(); |
- return HObjectAccess(kInobject, offset); |
+ return HObjectAccess(kInobject, offset, representation); |
} else { |
// Non-negative property indices are in the properties array. |
int offset = (index * kPointerSize) + FixedArray::kHeaderSize; |
- return HObjectAccess(kBackingStore, offset, name); |
+ return HObjectAccess(kBackingStore, offset, representation, name); |
} |
} |
HObjectAccess HObjectAccess::ForCellPayload(Isolate* isolate) { |
return HObjectAccess( |
- kInobject, Cell::kValueOffset, |
+ kInobject, Cell::kValueOffset, Representation::Tagged(), |
Handle<String>(isolate->heap()->cell_value_string())); |
} |