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:
parent
e59208527f
commit
4d1b2b1d38
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
237
src/hydrogen.cc
237
src/hydrogen.cc
@ -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(" ");
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user