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
parent e5920852
...@@ -858,22 +858,20 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, ...@@ -858,22 +858,20 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
// Shift operations can only deoptimize if we do a logical shift // Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32. // by 0 and the result cannot be truncated to int32.
bool can_deopt = (op == Token::SHR && constant_value == 0); bool may_deopt = (op == Token::SHR && constant_value == 0);
if (can_deopt) { bool does_deopt = false;
bool can_truncate = true; if (may_deopt) {
for (int i = 0; i < instr->uses()->length(); i++) { for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) { if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
can_truncate = false; does_deopt = true;
break; break;
} }
} }
can_deopt = !can_truncate;
} }
LInstruction* result = LInstruction* result =
DefineSameAsFirst(new LShiftI(op, left, right, can_deopt)); DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
if (can_deopt) AssignEnvironment(result); return does_deopt ? AssignEnvironment(result) : result;
return result;
} }
......
...@@ -264,31 +264,60 @@ HType HType::TypeFromValue(Handle<Object> value) { ...@@ -264,31 +264,60 @@ HType HType::TypeFromValue(Handle<Object> value) {
} }
int HValue::LookupOperandIndex(int occurrence_index, HValue* op) { bool HValue::IsDefinedAfter(HBasicBlock* other) const {
for (int i = 0; i < OperandCount(); ++i) { return block()->block_id() > other->block_id();
if (OperandAt(i) == op) { }
if (occurrence_index == 0) return i;
--occurrence_index;
} 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 -1;
} }
bool HValue::IsDefinedAfter(HBasicBlock* other) const { int HValue::UseCount() const {
return block()->block_id() > other->block_id(); int count = 0;
for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
return count;
} }
bool HValue::UsesMultipleTimes(HValue* op) { HUseListNode* HValue::RemoveUse(HValue* value, int index) {
bool seen = false; HUseListNode* previous = NULL;
for (int i = 0; i < OperandCount(); ++i) { HUseListNode* current = use_list_;
if (OperandAt(i) == op) { while (current != NULL) {
if (seen) return true; if (current->value() == value && current->index() == index) {
seen = true; if (previous == NULL) {
use_list_ = current->tail();
} else {
previous->set_tail(current->tail());
} }
break;
} }
return false;
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) { ...@@ -335,64 +364,31 @@ void HValue::SetOperandAt(int index, HValue* value) {
} }
void HValue::ReplaceAndDelete(HValue* other) { void HValue::DeleteAndReplaceWith(HValue* other) {
if (other != NULL) ReplaceValue(other); // We replace all uses first, so Delete can assert that there are none.
Delete(); if (other != NULL) ReplaceAllUsesWith(other);
}
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() {
ASSERT(HasNoUses()); ASSERT(HasNoUses());
ClearOperands(); ClearOperands();
DeleteFromGraph(); DeleteFromGraph();
} }
void HValue::ReplaceAtUse(HValue* use, HValue* other) { void HValue::ReplaceAllUsesWith(HValue* other) {
for (int i = 0; i < use->OperandCount(); ++i) { while (use_list_ != NULL) {
if (use->OperandAt(i) == this) { HUseListNode* list_node = use_list_;
use->SetOperandAt(i, other); 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) { void HValue::ClearOperands() {
for (int i = 0; i < use->OperandCount(); ++i) { for (int i = 0; i < OperandCount(); ++i) {
if (use->OperandAt(i) == this) { SetOperandAt(i, NULL);
// Call internal method that does not update use lists. The caller is
// responsible for doing so.
use->InternalSetOperandAt(i, other);
}
} }
} }
...@@ -427,9 +423,20 @@ bool HValue::UpdateInferredType() { ...@@ -427,9 +423,20 @@ bool HValue::UpdateInferredType() {
void HValue::RegisterUse(int index, HValue* new_value) { void HValue::RegisterUse(int index, HValue* new_value) {
HValue* old_value = OperandAt(index); HValue* old_value = OperandAt(index);
if (old_value == new_value) return; 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) { 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) { ...@@ -926,7 +933,7 @@ void HPhi::PrintTo(StringStream* stream) {
stream->Add(" "); stream->Add(" ");
} }
stream->Add(" uses%d_%di_%dd_%dt]", stream->Add(" uses%d_%di_%dd_%dt]",
uses()->length(), UseCount(),
int32_non_phi_uses() + int32_indirect_uses(), int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(), double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses()); tagged_non_phi_uses() + tagged_indirect_uses());
...@@ -944,8 +951,8 @@ void HPhi::AddInput(HValue* value) { ...@@ -944,8 +951,8 @@ void HPhi::AddInput(HValue* value) {
bool HPhi::HasRealUses() { bool HPhi::HasRealUses() {
for (int i = 0; i < uses()->length(); i++) { for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
if (!uses()->at(i)->IsPhi()) return true; if (!it.value()->IsPhi()) return true;
} }
return false; return false;
} }
...@@ -978,12 +985,11 @@ void HPhi::DeleteFromGraph() { ...@@ -978,12 +985,11 @@ void HPhi::DeleteFromGraph() {
void HPhi::InitRealUses(int phi_id) { void HPhi::InitRealUses(int phi_id) {
// Initialize real uses. // Initialize real uses.
phi_id_ = phi_id; phi_id_ = phi_id;
for (int j = 0; j < uses()->length(); j++) { for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
HValue* use = uses()->at(j); HValue* value = it.value();
if (!use->IsPhi()) { if (!value->IsPhi()) {
int index = use->LookupOperandIndex(0, this); Representation rep = value->RequiredInputRepresentation(it.index());
Representation req_rep = use->RequiredInputRepresentation(index); ++non_phi_uses_[rep.kind()];
non_phi_uses_[req_rep.kind()]++;
} }
} }
} }
......
...@@ -403,6 +403,62 @@ class HType { ...@@ -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 { class HValue: public ZoneObject {
public: public:
static const int kNoNumber = -1; static const int kNoNumber = -1;
...@@ -473,6 +529,7 @@ class HValue: public ZoneObject { ...@@ -473,6 +529,7 @@ class HValue: public ZoneObject {
HValue() : block_(NULL), HValue() : block_(NULL),
id_(kNoNumber), id_(kNoNumber),
type_(HType::Tagged()), type_(HType::Tagged()),
use_list_(NULL),
range_(NULL), range_(NULL),
flags_(0) {} flags_(0) {}
virtual ~HValue() {} virtual ~HValue() {}
...@@ -483,7 +540,7 @@ class HValue: public ZoneObject { ...@@ -483,7 +540,7 @@ class HValue: public ZoneObject {
int id() const { return id_; } int id() const { return id_; }
void set_id(int id) { id_ = 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; } virtual bool EmitAtUses() { return false; }
Representation representation() const { return representation_; } Representation representation() const { return representation_; }
...@@ -498,7 +555,7 @@ class HValue: public ZoneObject { ...@@ -498,7 +555,7 @@ class HValue: public ZoneObject {
HType type() const { return type_; } HType type() const { return type_; }
void set_type(HType type) { void set_type(HType type) {
ASSERT(uses_.length() == 0); ASSERT(HasNoUses());
type_ = type; type_ = type;
} }
...@@ -524,16 +581,13 @@ class HValue: public ZoneObject { ...@@ -524,16 +581,13 @@ class HValue: public ZoneObject {
virtual HValue* OperandAt(int index) = 0; virtual HValue* OperandAt(int index) = 0;
void SetOperandAt(int index, HValue* value); void SetOperandAt(int index, HValue* value);
int LookupOperandIndex(int occurrence_index, HValue* op); void DeleteAndReplaceWith(HValue* other);
bool UsesMultipleTimes(HValue* op); bool HasNoUses() const { return use_list_ == NULL; }
bool HasMultipleUses() const {
void ReplaceAndDelete(HValue* other); return use_list_ != NULL && use_list_->tail() != NULL;
void ReplaceValue(HValue* other); }
void ReplaceAtUse(HValue* use, HValue* other); int UseCount() const;
void ReplaceFirstAtUse(HValue* use, HValue* other, Representation r);
bool HasNoUses() const { return uses_.is_empty(); }
void ClearOperands(); void ClearOperands();
void Delete();
int flags() const { return flags_; } int flags() const { return flags_; }
void SetFlag(Flag f) { flags_ |= (1 << f); } void SetFlag(Flag f) { flags_ |= (1 << f); }
...@@ -611,7 +665,12 @@ class HValue: public ZoneObject { ...@@ -611,7 +665,12 @@ class HValue: public ZoneObject {
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries); 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); void RegisterUse(int index, HValue* new_value);
HBasicBlock* block_; HBasicBlock* block_;
...@@ -622,7 +681,7 @@ class HValue: public ZoneObject { ...@@ -622,7 +681,7 @@ class HValue: public ZoneObject {
Representation representation_; Representation representation_;
HType type_; HType type_;
SmallPointerList<HValue> uses_; HUseListNode* use_list_;
Range* range_; Range* range_;
int flags_; int flags_;
...@@ -2257,7 +2316,7 @@ class HCompare: public HBinaryOperation { ...@@ -2257,7 +2316,7 @@ class HCompare: public HBinaryOperation {
void SetInputRepresentation(Representation r); void SetInputRepresentation(Representation r);
virtual bool EmitAtUses() { virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1); return !HasSideEffects() && !HasMultipleUses();
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
...@@ -2299,7 +2358,7 @@ class HCompareJSObjectEq: public HBinaryOperation { ...@@ -2299,7 +2358,7 @@ class HCompareJSObjectEq: public HBinaryOperation {
} }
virtual bool EmitAtUses() { virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1); return !HasSideEffects() && !HasMultipleUses();
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
...@@ -2322,7 +2381,7 @@ class HUnaryPredicate: public HUnaryOperation { ...@@ -2322,7 +2381,7 @@ class HUnaryPredicate: public HUnaryOperation {
} }
virtual bool EmitAtUses() { virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1); return !HasSideEffects() && !HasMultipleUses();
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
...@@ -2382,7 +2441,7 @@ class HIsConstructCall: public HTemplateInstruction<0> { ...@@ -2382,7 +2441,7 @@ class HIsConstructCall: public HTemplateInstruction<0> {
} }
virtual bool EmitAtUses() { virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1); return !HasSideEffects() && !HasMultipleUses();
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
...@@ -2504,7 +2563,7 @@ class HInstanceOf: public HTemplateInstruction<3> { ...@@ -2504,7 +2563,7 @@ class HInstanceOf: public HTemplateInstruction<3> {
HValue* right() { return OperandAt(2); } HValue* right() { return OperandAt(2); }
virtual bool EmitAtUses() { virtual bool EmitAtUses() {
return !HasSideEffects() && (uses()->length() <= 1); return !HasSideEffects() && !HasMultipleUses();
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
......
This diff is collapsed.
...@@ -277,11 +277,10 @@ class HGraph: public ZoneObject { ...@@ -277,11 +277,10 @@ class HGraph: public ZoneObject {
void InsertTypeConversions(HInstruction* instr); void InsertTypeConversions(HInstruction* instr);
void PropagateMinusZeroChecks(HValue* value, BitVector* visited); void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
void InsertRepresentationChangeForUse(HValue* value, void InsertRepresentationChangeForUse(HValue* value,
HValue* use, HValue* use_value,
int use_index,
Representation to); Representation to);
void InsertRepresentationChangesForValue(HValue* current, void InsertRepresentationChangesForValue(HValue* value);
ZoneList<HValue*>* value_list,
ZoneList<Representation>* rep_list);
void InferTypes(ZoneList<HValue*>* worklist); void InferTypes(ZoneList<HValue*>* worklist);
void InitializeInferredTypes(int from_inclusive, int to_inclusive); void InitializeInferredTypes(int from_inclusive, int to_inclusive);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor); void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
......
...@@ -852,24 +852,22 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, ...@@ -852,24 +852,22 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
right = UseFixed(right_value, ecx); right = UseFixed(right_value, ecx);
} }
// Shift operations can only deoptimize if we do a logical shift // Shift operations can only deoptimize if we do a logical shift by 0 and
// by 0 and the result cannot be truncated to int32. // the result cannot be truncated to int32.
bool can_deopt = (op == Token::SHR && constant_value == 0); bool may_deopt = (op == Token::SHR && constant_value == 0);
if (can_deopt) { bool does_deopt = false;
bool can_truncate = true; if (may_deopt) {
for (int i = 0; i < instr->uses()->length(); i++) { for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) { if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
can_truncate = false; does_deopt = true;
break; break;
} }
} }
can_deopt = !can_truncate;
} }
LShiftI* result = new LShiftI(op, left, right, can_deopt); LInstruction* result =
return can_deopt DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
? AssignEnvironment(DefineSameAsFirst(result)) return does_deopt ? AssignEnvironment(result) : result;
: DefineSameAsFirst(result);
} }
......
...@@ -851,24 +851,22 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, ...@@ -851,24 +851,22 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
right = UseFixed(right_value, rcx); right = UseFixed(right_value, rcx);
} }
// Shift operations can only deoptimize if we do a logical shift // Shift operations can only deoptimize if we do a logical shift by 0 and
// by 0 and the result cannot be truncated to int32. // the result cannot be truncated to int32.
bool can_deopt = (op == Token::SHR && constant_value == 0); bool may_deopt = (op == Token::SHR && constant_value == 0);
if (can_deopt) { bool does_deopt = false;
bool can_truncate = true; if (may_deopt) {
for (int i = 0; i < instr->uses()->length(); i++) { for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) { if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
can_truncate = false; does_deopt = true;
break; break;
} }
} }
can_deopt = !can_truncate;
} }
LShiftI* result = new LShiftI(op, left, right, can_deopt); LInstruction* result =
return can_deopt DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
? AssignEnvironment(DefineSameAsFirst(result)) return does_deopt ? AssignEnvironment(result) : result;
: DefineSameAsFirst(result);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment