Change the Hydrogen representation of uses.

Rather than representing a use as a pointer to an HValue and then searching
for the specific (ambiguous) operand, we now represent a use as a pair of an
HValue and the input operand index.  Additionally, use a linked list instead
of a growable array list since we never use random access.

This allows us to remove a bunch of similarly named and subtly different
functions from the HValue API.  The cost in extra zone allocation per use is
partially offset by reusing use list nodes when replacing a use of one value
with another.

R=danno@chromium.org,fschneider@chromium.org

Review URL: http://codereview.chromium.org/6881044

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7674 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2011-04-20 10:38:08 +00:00
parent e59208527f
commit 4d1b2b1d38
7 changed files with 273 additions and 294 deletions

View File

@ -858,22 +858,20 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
// Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
bool can_deopt = (op == Token::SHR && constant_value == 0);
if (can_deopt) {
bool can_truncate = true;
for (int i = 0; i < instr->uses()->length(); i++) {
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
can_truncate = false;
bool may_deopt = (op == Token::SHR && constant_value == 0);
bool does_deopt = false;
if (may_deopt) {
for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
does_deopt = true;
break;
}
}
can_deopt = !can_truncate;
}
LInstruction* result =
DefineSameAsFirst(new LShiftI(op, left, right, can_deopt));
if (can_deopt) AssignEnvironment(result);
return result;
DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
return does_deopt ? AssignEnvironment(result) : result;
}

View File

@ -264,31 +264,60 @@ HType HType::TypeFromValue(Handle<Object> value) {
}
int HValue::LookupOperandIndex(int occurrence_index, HValue* op) {
for (int i = 0; i < OperandCount(); ++i) {
if (OperandAt(i) == op) {
if (occurrence_index == 0) return i;
--occurrence_index;
}
}
return -1;
}
bool HValue::IsDefinedAfter(HBasicBlock* other) const {
return block()->block_id() > other->block_id();
}
bool HValue::UsesMultipleTimes(HValue* op) {
bool seen = false;
for (int i = 0; i < OperandCount(); ++i) {
if (OperandAt(i) == op) {
if (seen) return true;
seen = true;
}
HUseIterator::HUseIterator(HUseListNode* head) : next_(head) {
Advance();
}
void HUseIterator::Advance() {
current_ = next_;
if (current_ != NULL) {
next_ = current_->tail();
value_ = current_->value();
index_ = current_->index();
}
return false;
}
int HValue::UseCount() const {
int count = 0;
for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
return count;
}
HUseListNode* HValue::RemoveUse(HValue* value, int index) {
HUseListNode* previous = NULL;
HUseListNode* current = use_list_;
while (current != NULL) {
if (current->value() == value && current->index() == index) {
if (previous == NULL) {
use_list_ = current->tail();
} else {
previous->set_tail(current->tail());
}
break;
}
previous = current;
current = current->tail();
}
#ifdef DEBUG
// Do not reuse use list nodes in debug mode, zap them.
if (current != NULL) {
HUseListNode* temp =
new HUseListNode(current->value(), current->index(), NULL);
current->Zap();
current = temp;
}
#endif
return current;
}
@ -335,64 +364,31 @@ void HValue::SetOperandAt(int index, HValue* value) {
}
void HValue::ReplaceAndDelete(HValue* other) {
if (other != NULL) ReplaceValue(other);
Delete();
}
void HValue::ReplaceValue(HValue* other) {
for (int i = 0; i < uses_.length(); ++i) {
HValue* use = uses_[i];
ASSERT(!use->block()->IsStartBlock());
InternalReplaceAtUse(use, other);
other->uses_.Add(use);
}
uses_.Rewind(0);
}
void HValue::ClearOperands() {
for (int i = 0; i < OperandCount(); ++i) {
SetOperandAt(i, NULL);
}
}
void HValue::Delete() {
void HValue::DeleteAndReplaceWith(HValue* other) {
// We replace all uses first, so Delete can assert that there are none.
if (other != NULL) ReplaceAllUsesWith(other);
ASSERT(HasNoUses());
ClearOperands();
DeleteFromGraph();
}
void HValue::ReplaceAtUse(HValue* use, HValue* other) {
for (int i = 0; i < use->OperandCount(); ++i) {
if (use->OperandAt(i) == this) {
use->SetOperandAt(i, other);
}
void HValue::ReplaceAllUsesWith(HValue* other) {
while (use_list_ != NULL) {
HUseListNode* list_node = use_list_;
HValue* value = list_node->value();
ASSERT(!value->block()->IsStartBlock());
value->InternalSetOperandAt(list_node->index(), other);
use_list_ = list_node->tail();
list_node->set_tail(other->use_list_);
other->use_list_ = list_node;
}
}
void HValue::ReplaceFirstAtUse(HValue* use, HValue* other, Representation r) {
for (int i = 0; i < use->OperandCount(); ++i) {
if (use->RequiredInputRepresentation(i).Equals(r) &&
use->OperandAt(i) == this) {
use->SetOperandAt(i, other);
return;
}
}
}
void HValue::InternalReplaceAtUse(HValue* use, HValue* other) {
for (int i = 0; i < use->OperandCount(); ++i) {
if (use->OperandAt(i) == this) {
// Call internal method that does not update use lists. The caller is
// responsible for doing so.
use->InternalSetOperandAt(i, other);
}
void HValue::ClearOperands() {
for (int i = 0; i < OperandCount(); ++i) {
SetOperandAt(i, NULL);
}
}
@ -427,9 +423,20 @@ bool HValue::UpdateInferredType() {
void HValue::RegisterUse(int index, HValue* new_value) {
HValue* old_value = OperandAt(index);
if (old_value == new_value) return;
if (old_value != NULL) old_value->uses_.RemoveElement(this);
HUseListNode* removed = NULL;
if (old_value != NULL) {
removed = old_value->RemoveUse(this, index);
}
if (new_value != NULL) {
new_value->uses_.Add(this);
if (removed == NULL) {
new_value->use_list_ =
new HUseListNode(this, index, new_value->use_list_);
} else {
removed->set_tail(new_value->use_list_);
new_value->use_list_ = removed;
}
}
}
@ -926,7 +933,7 @@ void HPhi::PrintTo(StringStream* stream) {
stream->Add(" ");
}
stream->Add(" uses%d_%di_%dd_%dt]",
uses()->length(),
UseCount(),
int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses());
@ -944,8 +951,8 @@ void HPhi::AddInput(HValue* value) {
bool HPhi::HasRealUses() {
for (int i = 0; i < uses()->length(); i++) {
if (!uses()->at(i)->IsPhi()) return true;
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
if (!it.value()->IsPhi()) return true;
}
return false;
}
@ -978,12 +985,11 @@ void HPhi::DeleteFromGraph() {
void HPhi::InitRealUses(int phi_id) {
// Initialize real uses.
phi_id_ = phi_id;
for (int j = 0; j < uses()->length(); j++) {
HValue* use = uses()->at(j);
if (!use->IsPhi()) {
int index = use->LookupOperandIndex(0, this);
Representation req_rep = use->RequiredInputRepresentation(index);
non_phi_uses_[req_rep.kind()]++;
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
HValue* value = it.value();
if (!value->IsPhi()) {
Representation rep = value->RequiredInputRepresentation(it.index());
++non_phi_uses_[rep.kind()];
}
}
}

View File

@ -403,6 +403,62 @@ class HType {
};
class HUseListNode: public ZoneObject {
public:
HUseListNode(HValue* value, int index, HUseListNode* tail)
: tail_(tail), value_(value), index_(index) {
}
HUseListNode* tail() const { return tail_; }
HValue* value() const { return value_; }
int index() const { return index_; }
void set_tail(HUseListNode* list) { tail_ = list; }
#ifdef DEBUG
void Zap() {
tail_ = reinterpret_cast<HUseListNode*>(1);
value_ = NULL;
index_ = -1;
}
#endif
private:
HUseListNode* tail_;
HValue* value_;
int index_;
};
// We reuse use list nodes behind the scenes as uses are added and deleted.
// This class is the safe way to iterate uses while deleting them.
class HUseIterator BASE_EMBEDDED {
public:
bool Done() { return current_ == NULL; }
void Advance();
HValue* value() {
ASSERT(!Done());
return value_;
}
int index() {
ASSERT(!Done());
return index_;
}
private:
explicit HUseIterator(HUseListNode* head);
HUseListNode* current_;
HUseListNode* next_;
HValue* value_;
int index_;
friend class HValue;
};
class HValue: public ZoneObject {
public:
static const int kNoNumber = -1;
@ -473,6 +529,7 @@ class HValue: public ZoneObject {
HValue() : block_(NULL),
id_(kNoNumber),
type_(HType::Tagged()),
use_list_(NULL),
range_(NULL),
flags_(0) {}
virtual ~HValue() {}
@ -483,7 +540,7 @@ class HValue: public ZoneObject {
int id() const { return id_; }
void set_id(int id) { id_ = id; }
SmallPointerList<HValue>* uses() { return &uses_; }
HUseIterator uses() const { return HUseIterator(use_list_); }
virtual bool EmitAtUses() { return false; }
Representation representation() const { return representation_; }
@ -498,7 +555,7 @@ class HValue: public ZoneObject {
HType type() const { return type_; }
void set_type(HType type) {
ASSERT(uses_.length() == 0);
ASSERT(HasNoUses());
type_ = type;
}
@ -524,16 +581,13 @@ class HValue: public ZoneObject {
virtual HValue* OperandAt(int index) = 0;
void SetOperandAt(int index, HValue* value);
int LookupOperandIndex(int occurrence_index, HValue* op);
bool UsesMultipleTimes(HValue* op);
void ReplaceAndDelete(HValue* other);
void ReplaceValue(HValue* other);
void ReplaceAtUse(HValue* use, HValue* other);
void ReplaceFirstAtUse(HValue* use, HValue* other, Representation r);
bool HasNoUses() const { return uses_.is_empty(); }
void DeleteAndReplaceWith(HValue* other);
bool HasNoUses() const { return use_list_ == NULL; }
bool HasMultipleUses() const {
return use_list_ != NULL && use_list_->tail() != NULL;
}
int UseCount() const;
void ClearOperands();
void Delete();
int flags() const { return flags_; }
void SetFlag(Flag f) { flags_ |= (1 << f); }
@ -611,7 +665,12 @@ class HValue: public ZoneObject {
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
}
void InternalReplaceAtUse(HValue* use, HValue* other);
// Remove the matching use from the use list if present. Returns the
// removed list node or NULL.
HUseListNode* RemoveUse(HValue* value, int index);
void ReplaceAllUsesWith(HValue* other);
void RegisterUse(int index, HValue* new_value);
HBasicBlock* block_;
@ -622,7 +681,7 @@ class HValue: public ZoneObject {
Representation representation_;
HType type_;
SmallPointerList<HValue> uses_;
HUseListNode* use_list_;
Range* range_;
int flags_;
@ -2257,7 +2316,7 @@ class HCompare: public HBinaryOperation {
void SetInputRepresentation(Representation r);
virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@ -2299,7 +2358,7 @@ class HCompareJSObjectEq: public HBinaryOperation {
}
virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@ -2322,7 +2381,7 @@ class HUnaryPredicate: public HUnaryOperation {
}
virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@ -2382,7 +2441,7 @@ class HIsConstructCall: public HTemplateInstruction<0> {
}
virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@ -2504,7 +2563,7 @@ class HInstanceOf: public HTemplateInstruction<3> {
HValue* right() { return OperandAt(2); }
virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1);
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {

View File

@ -644,7 +644,7 @@ void HGraph::Canonicalize() {
HInstruction* instr = blocks()->at(i)->first();
while (instr != NULL) {
HValue* value = instr->Canonicalize();
if (value != instr) instr->ReplaceAndDelete(value);
if (value != instr) instr->DeleteAndReplaceWith(value);
instr = instr->next();
}
}
@ -726,9 +726,9 @@ void HGraph::AssignDominators() {
void HGraph::EliminateRedundantPhis() {
HPhase phase("Redundant phi elimination", this);
// Worklist of phis that can potentially be eliminated. Initialized
// with all phi nodes. When elimination of a phi node modifies
// another phi node the modified phi node is added to the worklist.
// Worklist of phis that can potentially be eliminated. Initialized with
// all phi nodes. When elimination of a phi node modifies another phi node
// the modified phi node is added to the worklist.
ZoneList<HPhi*> worklist(blocks_.length());
for (int i = 0; i < blocks_.length(); ++i) {
worklist.AddAll(*blocks_[i]->phis());
@ -742,18 +742,14 @@ void HGraph::EliminateRedundantPhis() {
if (block == NULL) continue;
// Get replacement value if phi is redundant.
HValue* value = phi->GetRedundantReplacement();
HValue* replacement = phi->GetRedundantReplacement();
if (value != NULL) {
// Iterate through uses finding the ones that should be
// replaced.
SmallPointerList<HValue>* uses = phi->uses();
while (!uses->is_empty()) {
HValue* use = uses->RemoveLast();
if (use != NULL) {
phi->ReplaceAtUse(use, value);
if (use->IsPhi()) worklist.Add(HPhi::cast(use));
}
if (replacement != NULL) {
// Iterate through the uses and replace them all.
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
HValue* value = it.value();
value->SetOperandAt(it.index(), replacement);
if (value->IsPhi()) worklist.Add(HPhi::cast(value));
}
block->RemovePhi(phi);
}
@ -831,8 +827,8 @@ void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
HValue* current = worklist->RemoveLast();
in_worklist.Remove(current->id());
if (current->UpdateInferredType()) {
for (int j = 0; j < current->uses()->length(); j++) {
HValue* use = current->uses()->at(j);
for (HUseIterator it(current->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
if (!in_worklist.Contains(use->id())) {
in_worklist.Add(use->id());
worklist->Add(use);
@ -1445,7 +1441,7 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
instr->Mnemonic(),
other->id(),
other->Mnemonic());
instr->ReplaceAndDelete(other);
instr->DeleteAndReplaceWith(other);
} else {
map->Add(instr);
}
@ -1529,12 +1525,12 @@ void HInferRepresentation::InferBasedOnInputs(HValue* current) {
}
void HInferRepresentation::AddDependantsToWorklist(HValue* current) {
for (int i = 0; i < current->uses()->length(); ++i) {
AddToWorklist(current->uses()->at(i));
void HInferRepresentation::AddDependantsToWorklist(HValue* value) {
for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
AddToWorklist(it.value());
}
for (int i = 0; i < current->OperandCount(); ++i) {
AddToWorklist(current->OperandAt(i));
for (int i = 0; i < value->OperandCount(); ++i) {
AddToWorklist(value->OperandAt(i));
}
}
@ -1543,37 +1539,30 @@ void HInferRepresentation::AddDependantsToWorklist(HValue* current) {
// given as the parameter has a benefit in terms of less necessary type
// conversions. If there is a benefit, then the representation of the value is
// specialized.
void HInferRepresentation::InferBasedOnUses(HValue* current) {
Representation r = current->representation();
if (r.IsSpecialization() || current->HasNoUses()) return;
ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
Representation new_rep = TryChange(current);
void HInferRepresentation::InferBasedOnUses(HValue* value) {
Representation r = value->representation();
if (r.IsSpecialization() || value->HasNoUses()) return;
ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation));
Representation new_rep = TryChange(value);
if (!new_rep.IsNone()) {
if (!current->representation().Equals(new_rep)) {
current->ChangeRepresentation(new_rep);
AddDependantsToWorklist(current);
if (!value->representation().Equals(new_rep)) {
value->ChangeRepresentation(new_rep);
AddDependantsToWorklist(value);
}
}
}
Representation HInferRepresentation::TryChange(HValue* current) {
Representation HInferRepresentation::TryChange(HValue* value) {
// Array of use counts for each representation.
int use_count[Representation::kNumRepresentations];
for (int i = 0; i < Representation::kNumRepresentations; i++) {
use_count[i] = 0;
}
int use_count[Representation::kNumRepresentations] = { 0 };
for (int i = 0; i < current->uses()->length(); ++i) {
HValue* use = current->uses()->at(i);
int index = use->LookupOperandIndex(0, current);
Representation req_rep = use->RequiredInputRepresentation(index);
if (req_rep.IsNone()) continue;
if (use->IsPhi()) {
HPhi* phi = HPhi::cast(use);
phi->AddIndirectUsesTo(&use_count[0]);
}
use_count[req_rep.kind()]++;
for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
Representation rep = use->RequiredInputRepresentation(it.index());
if (rep.IsNone()) continue;
if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]);
++use_count[rep.kind()];
}
int tagged_count = use_count[Representation::kTagged];
int double_count = use_count[Representation::kDouble];
@ -1581,7 +1570,7 @@ Representation HInferRepresentation::TryChange(HValue* current) {
int non_tagged_count = double_count + int32_count;
// If a non-loop phi has tagged uses, don't convert it to untagged.
if (current->IsPhi() && !current->block()->IsLoopHeader()) {
if (value->IsPhi() && !value->block()->IsLoopHeader()) {
if (tagged_count > 0) return Representation::None();
}
@ -1602,41 +1591,39 @@ Representation HInferRepresentation::TryChange(HValue* current) {
void HInferRepresentation::Analyze() {
HPhase phase("Infer representations", graph_);
// (1) Initialize bit vectors and count real uses. Each phi
// gets a bit-vector of length <number of phis>.
// (1) Initialize bit vectors and count real uses. Each phi gets a
// bit-vector of length <number of phis>.
const ZoneList<HPhi*>* phi_list = graph_->phi_list();
int num_phis = phi_list->length();
ScopedVector<BitVector*> connected_phis(num_phis);
for (int i = 0; i < num_phis; i++) {
int phi_count = phi_list->length();
ScopedVector<BitVector*> connected_phis(phi_count);
for (int i = 0; i < phi_count; ++i) {
phi_list->at(i)->InitRealUses(i);
connected_phis[i] = new(zone()) BitVector(num_phis);
connected_phis[i] = new(zone()) BitVector(phi_count);
connected_phis[i]->Add(i);
}
// (2) Do a fixed point iteration to find the set of connected phis.
// A phi is connected to another phi if its value is used either
// directly or indirectly through a transitive closure of the def-use
// relation.
// (2) Do a fixed point iteration to find the set of connected phis. A
// phi is connected to another phi if its value is used either directly or
// indirectly through a transitive closure of the def-use relation.
bool change = true;
while (change) {
change = false;
for (int i = 0; i < num_phis; i++) {
for (int i = 0; i < phi_count; ++i) {
HPhi* phi = phi_list->at(i);
for (int j = 0; j < phi->uses()->length(); j++) {
HValue* use = phi->uses()->at(j);
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
if (use->IsPhi()) {
int phi_use = HPhi::cast(use)->phi_id();
if (connected_phis[i]->UnionIsChanged(*connected_phis[phi_use])) {
change = true;
}
int id = HPhi::cast(use)->phi_id();
change = change ||
connected_phis[i]->UnionIsChanged(*connected_phis[id]);
}
}
}
}
// (3) Sum up the non-phi use counts of all connected phis.
// Don't include the non-phi uses of the phi itself.
for (int i = 0; i < num_phis; i++) {
// (3) Sum up the non-phi use counts of all connected phis. Don't include
// the non-phi uses of the phi itself.
for (int i = 0; i < phi_count; ++i) {
HPhi* phi = phi_list->at(i);
for (BitVector::Iterator it(connected_phis.at(i));
!it.Done();
@ -1746,17 +1733,16 @@ void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
void HGraph::InsertRepresentationChangeForUse(HValue* value,
HValue* use,
HValue* use_value,
int use_index,
Representation to) {
// Insert the representation change right before its use. For phi-uses we
// insert at the end of the corresponding predecessor.
HInstruction* next = NULL;
if (use->IsPhi()) {
int index = 0;
while (use->OperandAt(index) != value) ++index;
next = use->block()->predecessors()->at(index)->end();
if (use_value->IsPhi()) {
next = use_value->block()->predecessors()->at(use_index)->end();
} else {
next = HInstruction::cast(use);
next = HInstruction::cast(use_value);
}
// For constants we try to make the representation change at compile
@ -1764,7 +1750,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
// information we treat constants like normal instructions and insert the
// change instructions for them.
HInstruction* new_value = NULL;
bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32);
bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
// Try to create a new copy of the constant with the new representation.
@ -1779,89 +1765,26 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
}
new_value->InsertBefore(next);
value->ReplaceFirstAtUse(use, new_value, to);
use_value->SetOperandAt(use_index, new_value);
}
int CompareConversionUses(HValue* a,
HValue* b,
Representation a_rep,
Representation b_rep) {
if (a_rep.kind() > b_rep.kind()) {
// Make sure specializations are separated in the result array.
return 1;
}
// Put truncating conversions before non-truncating conversions.
bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32);
bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32);
if (a_truncate != b_truncate) {
return a_truncate ? -1 : 1;
}
// Sort by increasing block ID.
return a->block()->block_id() - b->block()->block_id();
}
void HGraph::InsertRepresentationChangesForValue(
HValue* current,
ZoneList<HValue*>* to_convert,
ZoneList<Representation>* to_convert_reps) {
Representation r = current->representation();
void HGraph::InsertRepresentationChangesForValue(HValue* value) {
Representation r = value->representation();
if (r.IsNone()) return;
if (current->uses()->is_empty()) return;
if (value->HasNoUses()) return;
// Collect the representation changes in a sorted list. This allows
// us to avoid duplicate changes without searching the list.
ASSERT(to_convert->is_empty());
ASSERT(to_convert_reps->is_empty());
for (int i = 0; i < current->uses()->length(); ++i) {
HValue* use = current->uses()->at(i);
// The occurrences index means the index within the operand array of "use"
// at which "current" is used. While iterating through the use array we
// also have to iterate over the different occurrence indices.
int occurrence_index = 0;
if (use->UsesMultipleTimes(current)) {
occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1);
if (FLAG_trace_representation) {
PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n",
current->id(),
use->id(),
occurrence_index);
}
}
int operand_index = use->LookupOperandIndex(occurrence_index, current);
Representation req = use->RequiredInputRepresentation(operand_index);
for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
HValue* use_value = it.value();
int use_index = it.index();
Representation req = use_value->RequiredInputRepresentation(use_index);
if (req.IsNone() || req.Equals(r)) continue;
int index = 0;
while (index < to_convert->length() &&
CompareConversionUses(to_convert->at(index),
use,
to_convert_reps->at(index),
req) < 0) {
++index;
}
if (FLAG_trace_representation) {
PrintF("Inserting a representation change to %s of %d for use at %d\n",
req.Mnemonic(),
current->id(),
use->id());
}
to_convert->InsertAt(index, use);
to_convert_reps->InsertAt(index, req);
InsertRepresentationChangeForUse(value, use_value, use_index, req);
}
for (int i = 0; i < to_convert->length(); ++i) {
HValue* use = to_convert->at(i);
Representation r_to = to_convert_reps->at(i);
InsertRepresentationChangeForUse(current, use, r_to);
if (value->HasNoUses()) {
ASSERT(value->IsConstant());
value->DeleteAndReplaceWith(NULL);
}
if (current->uses()->is_empty()) {
ASSERT(current->IsConstant());
current->Delete();
}
to_convert->Rewind(0);
to_convert_reps->Rewind(0);
}
@ -1886,8 +1809,8 @@ void HGraph::InsertRepresentationChanges() {
for (int i = 0; i < phi_list()->length(); i++) {
HPhi* phi = phi_list()->at(i);
if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
for (int j = 0; j < phi->uses()->length(); j++) {
HValue* use = phi->uses()->at(j);
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
if (!use->CheckFlag(HValue::kTruncatingToInt32)) {
phi->ClearFlag(HValue::kTruncatingToInt32);
change = true;
@ -1897,19 +1820,17 @@ void HGraph::InsertRepresentationChanges() {
}
}
ZoneList<HValue*> value_list(4);
ZoneList<Representation> rep_list(4);
for (int i = 0; i < blocks_.length(); ++i) {
// Process phi instructions first.
for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
HPhi* phi = blocks_[i]->phis()->at(j);
InsertRepresentationChangesForValue(phi, &value_list, &rep_list);
const ZoneList<HPhi*>* phis = blocks_[i]->phis();
for (int j = 0; j < phis->length(); j++) {
InsertRepresentationChangesForValue(phis->at(j));
}
// Process normal instructions.
HInstruction* current = blocks_[i]->first();
while (current != NULL) {
InsertRepresentationChangesForValue(current, &value_list, &rep_list);
InsertRepresentationChangesForValue(current);
current = current->next();
}
}
@ -5943,7 +5864,7 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
HInstruction* instruction = current->first();
while (instruction != NULL) {
int bci = 0;
int uses = instruction->uses()->length();
int uses = instruction->UseCount();
trace_.Add("%d %d ", bci, uses);
instruction->PrintNameTo(&trace_);
trace_.Add(" ");

View File

@ -277,11 +277,10 @@ class HGraph: public ZoneObject {
void InsertTypeConversions(HInstruction* instr);
void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
void InsertRepresentationChangeForUse(HValue* value,
HValue* use,
HValue* use_value,
int use_index,
Representation to);
void InsertRepresentationChangesForValue(HValue* current,
ZoneList<HValue*>* value_list,
ZoneList<Representation>* rep_list);
void InsertRepresentationChangesForValue(HValue* value);
void InferTypes(ZoneList<HValue*>* worklist);
void InitializeInferredTypes(int from_inclusive, int to_inclusive);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);

View File

@ -852,24 +852,22 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
right = UseFixed(right_value, ecx);
}
// Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
bool can_deopt = (op == Token::SHR && constant_value == 0);
if (can_deopt) {
bool can_truncate = true;
for (int i = 0; i < instr->uses()->length(); i++) {
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
can_truncate = false;
// Shift operations can only deoptimize if we do a logical shift by 0 and
// the result cannot be truncated to int32.
bool may_deopt = (op == Token::SHR && constant_value == 0);
bool does_deopt = false;
if (may_deopt) {
for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
does_deopt = true;
break;
}
}
can_deopt = !can_truncate;
}
LShiftI* result = new LShiftI(op, left, right, can_deopt);
return can_deopt
? AssignEnvironment(DefineSameAsFirst(result))
: DefineSameAsFirst(result);
LInstruction* result =
DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
return does_deopt ? AssignEnvironment(result) : result;
}

View File

@ -851,24 +851,22 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
right = UseFixed(right_value, rcx);
}
// Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
bool can_deopt = (op == Token::SHR && constant_value == 0);
if (can_deopt) {
bool can_truncate = true;
for (int i = 0; i < instr->uses()->length(); i++) {
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
can_truncate = false;
// Shift operations can only deoptimize if we do a logical shift by 0 and
// the result cannot be truncated to int32.
bool may_deopt = (op == Token::SHR && constant_value == 0);
bool does_deopt = false;
if (may_deopt) {
for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
does_deopt = true;
break;
}
}
can_deopt = !can_truncate;
}
LShiftI* result = new LShiftI(op, left, right, can_deopt);
return can_deopt
? AssignEnvironment(DefineSameAsFirst(result))
: DefineSameAsFirst(result);
LInstruction* result =
DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
return does_deopt ? AssignEnvironment(result) : result;
}