Index: src/hydrogen-instructions.cc |
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc |
index feac1be0bcfcdf45f6c435f7899acd645d24e4e8..ec23e1971b7923d14b11ca23622cb900dbcbcd24 100644 |
--- a/src/hydrogen-instructions.cc |
+++ b/src/hydrogen-instructions.cc |
@@ -85,6 +85,81 @@ void HValue::AssumeRepresentation(Representation r) { |
} |
+void HValue::InferRepresentation(HInferRepresentation* h_infer) { |
+ ASSERT(CheckFlag(kFlexibleRepresentation)); |
+ Representation new_rep = RepresentationFromInputs(); |
+ UpdateRepresentation(new_rep, h_infer, "inputs"); |
+ new_rep = RepresentationFromUses(); |
+ UpdateRepresentation(new_rep, h_infer, "uses"); |
+} |
+ |
+ |
+Representation HValue::RepresentationFromUses() { |
+ if (HasNoUses()) return Representation::None(); |
+ |
+ // Array of use counts for each representation. |
+ int use_count[Representation::kNumRepresentations] = { 0 }; |
+ |
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
+ HValue* use = it.value(); |
+ Representation rep = use->observed_input_representation(it.index()); |
+ if (rep.IsNone()) continue; |
+ if (FLAG_trace_representation) { |
+ PrintF("#%d %s is used by #%d %s as %s%s\n", |
+ id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(), |
+ (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); |
+ } |
+ use_count[rep.kind()] += use->LoopWeight(); |
+ } |
+ if (IsPhi()) HPhi::cast(this)->AddIndirectUsesTo(&use_count[0]); |
+ int tagged_count = use_count[Representation::kTagged]; |
+ int double_count = use_count[Representation::kDouble]; |
+ int int32_count = use_count[Representation::kInteger32]; |
+ |
+ if (tagged_count > 0) return Representation::Tagged(); |
+ if (double_count > 0) return Representation::Double(); |
+ if (int32_count > 0) return Representation::Integer32(); |
+ |
+ return Representation::None(); |
+} |
+ |
+ |
+void HValue::UpdateRepresentation(Representation new_rep, |
+ HInferRepresentation* h_infer, |
+ const char* reason) { |
+ Representation r = representation(); |
+ if (new_rep.is_more_general_than(r)) { |
+ // When an HConstant is marked "not convertible to integer", then |
+ // never try to represent it as an integer. |
+ if (new_rep.IsInteger32() && !IsConvertibleToInteger()) { |
+ new_rep = Representation::Tagged(); |
+ if (FLAG_trace_representation) { |
+ PrintF("Changing #%d %s representation %s -> %s because it's NCTI" |
+ " (%s want i)\n", |
+ id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason); |
+ } |
+ } else { |
+ if (FLAG_trace_representation) { |
+ PrintF("Changing #%d %s representation %s -> %s based on %s\n", |
+ id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason); |
+ } |
+ } |
+ ChangeRepresentation(new_rep); |
+ AddDependantsToWorklist(h_infer); |
+ } |
+} |
+ |
+ |
+void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) { |
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
+ h_infer->AddToWorklist(it.value()); |
+ } |
+ for (int i = 0; i < OperandCount(); ++i) { |
+ h_infer->AddToWorklist(OperandAt(i)); |
+ } |
+} |
+ |
+ |
static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { |
if (result > kMaxInt) { |
*overflow = true; |
@@ -301,6 +376,7 @@ HUseListNode* HUseListNode::tail() { |
bool HValue::CheckUsesForFlag(Flag f) { |
for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
+ if (it.value()->IsSimulate()) continue; |
if (!it.value()->CheckFlag(f)) return false; |
} |
return true; |
@@ -764,6 +840,24 @@ void HReturn::PrintDataTo(StringStream* stream) { |
} |
+Representation HBranch::observed_input_representation(int index) { |
+ static const ToBooleanStub::Types tagged_types( |
+ ToBooleanStub::UNDEFINED | |
+ ToBooleanStub::NULL_TYPE | |
+ ToBooleanStub::SPEC_OBJECT | |
+ ToBooleanStub::STRING); |
+ if (expected_input_types_.ContainsAnyOf(tagged_types)) { |
+ return Representation::Tagged(); |
+ } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) { |
+ return Representation::Double(); |
+ } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) { |
+ return Representation::Integer32(); |
+ } else { |
+ return Representation::None(); |
+ } |
+} |
+ |
+ |
void HCompareMap::PrintDataTo(StringStream* stream) { |
value()->PrintNameTo(stream); |
stream->Add(" (%p)", *map()); |
@@ -1339,15 +1433,11 @@ void HPhi::InitRealUses(int phi_id) { |
for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
HValue* value = it.value(); |
if (!value->IsPhi()) { |
- Representation rep = value->ObservedInputRepresentation(it.index()); |
+ Representation rep = value->observed_input_representation(it.index()); |
non_phi_uses_[rep.kind()] += value->LoopWeight(); |
if (FLAG_trace_representation) { |
- PrintF("%d %s is used by %d %s as %s\n", |
- this->id(), |
- this->Mnemonic(), |
- value->id(), |
- value->Mnemonic(), |
- rep.Mnemonic()); |
+ PrintF("#%d Phi is used by real #%d %s as %s\n", |
+ id(), value->id(), value->Mnemonic(), rep.Mnemonic()); |
} |
} |
} |
@@ -1356,11 +1446,8 @@ void HPhi::InitRealUses(int phi_id) { |
void HPhi::AddNonPhiUsesFrom(HPhi* other) { |
if (FLAG_trace_representation) { |
- PrintF("adding to %d %s uses of %d %s: i%d d%d t%d\n", |
- this->id(), |
- this->Mnemonic(), |
- other->id(), |
- other->Mnemonic(), |
+ PrintF("adding to #%d Phi uses of #%d Phi: i%d d%d t%d\n", |
+ id(), other->id(), |
other->non_phi_uses_[Representation::kInteger32], |
other->non_phi_uses_[Representation::kDouble], |
other->non_phi_uses_[Representation::kTagged]); |
@@ -1379,9 +1466,20 @@ void HPhi::AddIndirectUsesTo(int* dest) { |
} |
-void HPhi::ResetInteger32Uses() { |
- non_phi_uses_[Representation::kInteger32] = 0; |
- indirect_uses_[Representation::kInteger32] = 0; |
+void HSimulate::MergeInto(HSimulate* other) { |
+ for (int i = 0; i < values_.length(); ++i) { |
+ HValue* value = values_[i]; |
+ if (HasAssignedIndexAt(i)) { |
+ other->AddAssignedValue(GetAssignedIndexAt(i), value); |
+ } else { |
+ if (other->pop_count_ > 0) { |
+ other->pop_count_--; |
+ } else { |
+ other->AddPushedValue(value); |
+ } |
+ } |
+ } |
+ other->pop_count_ += pop_count(); |
} |
@@ -1390,7 +1488,7 @@ void HSimulate::PrintDataTo(StringStream* stream) { |
if (pop_count_ > 0) stream->Add(" pop %d", pop_count_); |
if (values_.length() > 0) { |
if (pop_count_ > 0) stream->Add(" /"); |
- for (int i = 0; i < values_.length(); ++i) { |
+ for (int i = values_.length() - 1; i >= 0; --i) { |
if (i > 0) stream->Add(","); |
if (HasAssignedIndexAt(i)) { |
stream->Add(" var[%d] = ", GetAssignedIndexAt(i)); |
@@ -1429,7 +1527,6 @@ HConstant::HConstant(Handle<Object> handle, Representation r) |
: handle_(handle), |
has_int32_value_(false), |
has_double_value_(false) { |
- set_representation(r); |
SetFlag(kUseGVN); |
if (handle_->IsNumber()) { |
double n = handle_->Number(); |
@@ -1438,6 +1535,16 @@ HConstant::HConstant(Handle<Object> handle, Representation r) |
double_value_ = n; |
has_double_value_ = true; |
} |
+ if (r.IsNone()) { |
+ if (has_int32_value_) { |
+ r = Representation::Integer32(); |
+ } else if (has_double_value_) { |
+ r = Representation::Double(); |
+ } else { |
+ r = Representation::Tagged(); |
+ } |
+ } |
+ set_representation(r); |
} |
@@ -1536,6 +1643,52 @@ void HBinaryOperation::PrintDataTo(StringStream* stream) { |
} |
+void HBinaryOperation::InferRepresentation(HInferRepresentation* 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"); |
+} |
+ |
+ |
+Representation HBinaryOperation::RepresentationFromInputs() { |
+ // Determine the worst case of observed input representations and |
+ // the currently assumed output representation. |
+ Representation rep = representation(); |
+ if (observed_output_representation_.is_more_general_than(rep)) { |
+ rep = observed_output_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; |
+ } |
+ // 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.is_more_general_than(rep) && |
+ left()->CheckFlag(kFlexibleRepresentation)) { |
+ rep = left_rep; |
+ } |
+ if (right_rep.is_more_general_than(rep) && |
+ right()->CheckFlag(kFlexibleRepresentation)) { |
+ rep = right_rep; |
+ } |
+ return rep; |
+} |
+ |
+ |
+void HBinaryOperation::AssumeRepresentation(Representation r) { |
+ set_observed_input_representation(r, r); |
+ HValue::AssumeRepresentation(r); |
+} |
+ |
+ |
Range* HBitwise::InferRange(Zone* zone) { |
if (op() == Token::BIT_XOR) return HValue::InferRange(zone); |
const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff); |
@@ -1667,9 +1820,19 @@ void HGoto::PrintDataTo(StringStream* stream) { |
} |
-void HCompareIDAndBranch::SetInputRepresentation(Representation r) { |
- input_representation_ = r; |
- if (r.IsDouble()) { |
+void HCompareIDAndBranch::InferRepresentation(HInferRepresentation* h_infer) { |
+ Representation rep = Representation::None(); |
+ Representation left_rep = left()->representation(); |
+ Representation right_rep = right()->representation(); |
+ bool observed_integers = |
+ observed_input_representation(0).IsInteger32() && |
+ observed_input_representation(1).IsInteger32(); |
+ bool inputs_are_not_doubles = |
+ !left_rep.IsDouble() && !right_rep.IsDouble(); |
+ if (observed_integers && inputs_are_not_doubles) { |
+ rep = Representation::Integer32(); |
+ } else { |
+ rep = Representation::Double(); |
// According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, === |
// and !=) have special handling of undefined, e.g. undefined == undefined |
// is 'true'. Relational comparisons have a different semantic, first |
@@ -1686,9 +1849,8 @@ void HCompareIDAndBranch::SetInputRepresentation(Representation r) { |
if (!Token::IsOrderedRelationalCompareOp(token_)) { |
SetFlag(kDeoptimizeOnUndefined); |
} |
- } else { |
- ASSERT(r.IsInteger32()); |
} |
+ ChangeRepresentation(rep); |
} |
@@ -2451,7 +2613,41 @@ void HBitwise::PrintDataTo(StringStream* stream) { |
} |
-Representation HPhi::InferredRepresentation() { |
+void HPhi::InferRepresentation(HInferRepresentation* h_infer) { |
+ ASSERT(CheckFlag(kFlexibleRepresentation)); |
+ // If there are non-Phi uses, and all of them have observed the same |
+ // representation, than that's what this Phi is going to use. |
+ Representation new_rep = RepresentationObservedByAllNonPhiUses(); |
+ if (!new_rep.IsNone()) { |
+ UpdateRepresentation(new_rep, h_infer, "unanimous use observations"); |
+ return; |
+ } |
+ new_rep = RepresentationFromInputs(); |
+ UpdateRepresentation(new_rep, h_infer, "inputs"); |
+ new_rep = RepresentationFromUses(); |
+ UpdateRepresentation(new_rep, h_infer, "uses"); |
+ new_rep = RepresentationFromUseRequirements(); |
+ UpdateRepresentation(new_rep, h_infer, "use requirements"); |
+} |
+ |
+ |
+Representation HPhi::RepresentationObservedByAllNonPhiUses() { |
+ int non_phi_use_count = 0; |
+ for (int i = Representation::kInteger32; |
+ i < Representation::kNumRepresentations; ++i) { |
+ non_phi_use_count += non_phi_uses_[i]; |
+ } |
+ if (non_phi_use_count <= 1) return Representation::None(); |
+ for (int i = 0; i < Representation::kNumRepresentations; ++i) { |
+ if (non_phi_uses_[i] == non_phi_use_count) { |
+ return Representation::FromKind(static_cast<Representation::Kind>(i)); |
+ } |
+ } |
+ return Representation::None(); |
+} |
+ |
+ |
+Representation HPhi::RepresentationFromInputs() { |
bool double_occurred = false; |
bool int32_occurred = false; |
for (int i = 0; i < OperandCount(); ++i) { |
@@ -2460,6 +2656,7 @@ Representation HPhi::InferredRepresentation() { |
HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value(); |
if (hint_value != NULL) { |
Representation hint = hint_value->representation(); |
+ if (hint.IsTagged()) return hint; |
if (hint.IsDouble()) double_occurred = true; |
if (hint.IsInteger32()) int32_occurred = true; |
} |
@@ -2478,7 +2675,9 @@ Representation HPhi::InferredRepresentation() { |
return Representation::Tagged(); |
} |
} else { |
- return Representation::Tagged(); |
+ if (value->IsPhi() && !IsConvertibleToInteger()) { |
+ return Representation::Tagged(); |
+ } |
} |
} |
} |
@@ -2491,6 +2690,37 @@ Representation HPhi::InferredRepresentation() { |
} |
+Representation HPhi::RepresentationFromUseRequirements() { |
+ Representation all_uses_require = Representation::None(); |
+ bool all_uses_require_the_same = true; |
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) { |
+ // We check for observed_input_representation elsewhere. |
+ Representation use_rep = |
+ it.value()->RequiredInputRepresentation(it.index()); |
+ // No useful info from this use -> look at the next one. |
+ if (use_rep.IsNone()) { |
+ continue; |
+ } |
+ if (use_rep.Equals(all_uses_require)) { |
+ continue; |
+ } |
+ // This use's representation contradicts what we've seen so far. |
+ if (!all_uses_require.IsNone()) { |
+ ASSERT(!use_rep.Equals(all_uses_require)); |
+ all_uses_require_the_same = false; |
+ break; |
+ } |
+ // Otherwise, initialize observed representation. |
+ all_uses_require = use_rep; |
+ } |
+ if (all_uses_require_the_same) { |
+ return all_uses_require; |
+ } |
+ |
+ return Representation::None(); |
+} |
+ |
+ |
// Node-specific verification code is only included in debug mode. |
#ifdef DEBUG |