Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Unified Diff: runtime/vm/flow_graph_optimizer.cc

Issue 14872002: Improve load forwarding: (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/flow_graph_optimizer.cc
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 15847b4836cc186a5f429b06b47a5ebad49017d4..14d37c37e8d81952d3c088c45c73c4e491a94e2a 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -302,7 +302,8 @@ static void ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
}
-void FlowGraphOptimizer::Canonicalize() {
+bool FlowGraphOptimizer::Canonicalize() {
+ bool changed = false;
for (intptr_t i = 0; i < block_order_.length(); ++i) {
BlockEntryInstr* entry = block_order_[i];
entry->Accept(this);
@@ -314,9 +315,11 @@ void FlowGraphOptimizer::Canonicalize() {
// this.
ASSERT((replacement == NULL) || current->IsDefinition());
ReplaceCurrentInstruction(&it, current, replacement, flow_graph_);
+ changed = true;
}
}
}
+ return changed;
}
@@ -1275,12 +1278,12 @@ void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
field.Offset(),
AbstractType::ZoneHandle(field.type()),
field.is_final());
+ Field* the_field = &Field::ZoneHandle(field.raw());
+ load->set_field(the_field);
if (field.guarded_cid() != kIllegalCid) {
if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) {
load->set_result_cid(field.guarded_cid());
}
- Field* the_field = &Field::ZoneHandle(field.raw());
- load->set_field(the_field);
AddToGuardedFields(the_field);
}
load->set_field_name(String::Handle(field.name()).ToCString());
@@ -3290,22 +3293,23 @@ class Alias : public ValueObject {
return Alias(kIndexesAlias);
}
- // Field load/stores alias each other when field offset matches.
- // TODO(vegorov): use field information to disambiguate load/stores into
- // different fields that by accident share offset.
- static Alias Field(intptr_t offset_in_bytes) {
+ // Field load/stores alias each other only when they access the same field.
+ // AliasedSet assigns ids to a combination of instance and field during
+ // the optimization phase.
+ static Alias Field(intptr_t id) {
+ ASSERT(id >= kFirstFieldAlias);
+ return Alias(id * 2 + 1);
+ }
+
+ // VMField load/stores alias each other when field offset matches.
+ // TODO(vegorov) storing a context variable does not alias loading array
+ // length.
+ static Alias VMField(intptr_t offset_in_bytes) {
const intptr_t idx = offset_in_bytes / kWordSize;
ASSERT(idx >= kFirstFieldAlias);
return Alias(idx * 2);
}
- // Static field load/stores alias each other.
- // AliasedSet assigns ids to static fields during optimization phase.
- static Alias StaticField(intptr_t id) {
- ASSERT(id >= kFirstFieldAlias);
- return Alias(id * 2 + 1);
- }
-
// Current context load/stores alias each other.
static Alias CurrentContext() {
return Alias(kCurrentContextAlias);
@@ -3358,7 +3362,12 @@ class AliasedSet : public ZoneAllocated {
LoadFieldInstr* load_field = defn->AsLoadField();
if (load_field != NULL) {
- return Alias::Field(load_field->offset_in_bytes());
+ if (load_field->field() != NULL) {
+ Definition* instance = load_field->instance()->definition();
+ return Alias::Field(GetInstanceFieldId(instance, *load_field->field()));
+ } else {
+ return Alias::VMField(load_field->offset_in_bytes());
+ }
}
if (defn->IsCurrentContext()) {
@@ -3367,7 +3376,7 @@ class AliasedSet : public ZoneAllocated {
LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
if (load_static_field != NULL) {
- return Alias::StaticField(GetFieldId(load_static_field->field()));
+ return Alias::Field(GetFieldId(kAnyInstance, load_static_field->field()));
}
UNREACHABLE();
@@ -3382,12 +3391,14 @@ class AliasedSet : public ZoneAllocated {
StoreInstanceFieldInstr* store_instance_field =
instr->AsStoreInstanceField();
if (store_instance_field != NULL) {
- return Alias::Field(store_instance_field->field().Offset());
+ Definition* instance = store_instance_field->instance()->definition();
+ return Alias::Field(GetInstanceFieldId(instance,
+ store_instance_field->field()));
}
StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField();
if (store_vm_field != NULL) {
- return Alias::Field(store_vm_field->offset_in_bytes());
+ return Alias::VMField(store_vm_field->offset_in_bytes());
}
if (instr->IsStoreContext() || instr->IsChainContext()) {
@@ -3396,7 +3407,7 @@ class AliasedSet : public ZoneAllocated {
StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
if (store_static_field != NULL) {
- return Alias::StaticField(GetFieldId(store_static_field->field()));
+ return Alias::Field(GetStaticFieldId(store_static_field->field()));
}
return Alias::None();
@@ -3438,18 +3449,68 @@ class AliasedSet : public ZoneAllocated {
// Get id assigned to the given field. Assign a new id if the field is seen
// for the first time.
- intptr_t GetFieldId(const Field& field) {
- intptr_t id = field_ids_.Lookup(&field);
+ intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
+ intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field));
if (id == 0) {
id = ++max_field_id_;
- field_ids_.Insert(FieldIdPair(&field, id));
+ field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id));
}
return id;
}
+ enum {
+ kAnyInstance = -1
+ };
+
+ intptr_t GetInstanceFieldId(Definition* defn, const Field& field) {
+ intptr_t instance_id = kAnyInstance;
+
+ AllocateObjectInstr* alloc = defn->AsAllocateObject();
+ if ((alloc != NULL) && !CanBeAliased(alloc)) {
+ instance_id = alloc->ssa_temp_index();
+ ASSERT(instance_id != kAnyInstance);
+ }
+
+ return GetFieldId(instance_id, field);
+ }
+
+ intptr_t GetStaticFieldId(const Field& field) {
+ return GetFieldId(kAnyInstance, field);
+ }
+
+ intptr_t CanBeAliased(AllocateObjectInstr* alloc) {
+ if (alloc->identity() == AllocateObjectInstr::kUnknown) {
+ bool escapes = false;
+ for (Value* use = alloc->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ Instruction* instr = use->instruction();
+ if (instr->IsPushArgument() ||
+ (instr->IsStoreVMField() && use->use_index() != 0) ||
+ (instr->IsStoreInstanceField() && use->use_index() != 0) ||
srdjan 2013/05/02 21:00:54 Some more parentheses, please.
Vyacheslav Egorov (Google) 2013/05/02 21:20:25 Done.
+ (instr->IsStoreStaticField()) ||
+ (instr->IsPhi())) {
+ escapes = true;
+ break;
+ }
+
+ alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
+ : AllocateObjectInstr::kNotAliased);
+ }
+ }
+ return alloc->identity() != AllocateObjectInstr::kNotAliased;
+ }
+
class FieldIdPair {
public:
- typedef const Field* Key;
+ struct Key {
+ Key(intptr_t instance_id, const Field* field)
+ : instance_id_(instance_id), field_(field) { }
+
+ intptr_t instance_id_;
+ const Field* field_;
+ };
+
typedef intptr_t Value;
typedef FieldIdPair Pair;
@@ -3464,11 +3525,12 @@ class AliasedSet : public ZoneAllocated {
}
static intptr_t Hashcode(Key key) {
- return String::Handle(key->name()).Hash();
+ return String::Handle(key.field_->name()).Hash();
}
static inline bool IsKeyEqual(Pair kv, Key key) {
- return KeyOf(kv)->raw() == key->raw();
+ return (KeyOf(kv).field_->raw() == key.field_->raw()) &&
+ (KeyOf(kv).instance_id_ == key.instance_id_);
}
private:
@@ -3541,7 +3603,7 @@ class LoadKeyValueTrait {
location = store_indexed->index()->definition()->ssa_temp_index();
} else if (key->IsLoadField()) {
LoadFieldInstr* load_field = key->AsLoadField();
- object = load_field->value()->definition()->ssa_temp_index();
+ object = load_field->instance()->definition()->ssa_temp_index();
location = load_field->offset_in_bytes();
} else if (key->IsStoreInstanceField()) {
StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField();
@@ -3597,11 +3659,11 @@ class LoadKeyValueTrait {
LoadFieldInstr* load_field = kv->AsLoadField();
if (key->IsStoreVMField()) {
StoreVMFieldInstr* store_field = key->AsStoreVMField();
- return load_field->value()->Equals(store_field->dest()) &&
+ return load_field->instance()->Equals(store_field->dest()) &&
(load_field->offset_in_bytes() == store_field->offset_in_bytes());
} else if (key->IsStoreInstanceField()) {
StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField();
- return load_field->value()->Equals(store_field->instance()) &&
+ return load_field->instance()->Equals(store_field->instance()) &&
(load_field->offset_in_bytes() == store_field->field().Offset());
}
@@ -4727,16 +4789,16 @@ void ConstantPropagator::VisitLoadUntagged(LoadUntaggedInstr* instr) {
void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
- (instr->value()->definition()->IsCreateArray())) {
+ (instr->instance()->definition()->IsCreateArray())) {
const intptr_t length =
- instr->value()->definition()->AsCreateArray()->num_elements();
+ instr->instance()->definition()->AsCreateArray()->num_elements();
const Object& result = Smi::ZoneHandle(Smi::New(length));
SetValue(instr, result);
return;
}
if (instr->IsImmutableLengthLoad()) {
- ConstantInstr* constant = instr->value()->definition()->AsConstant();
+ ConstantInstr* constant = instr->instance()->definition()->AsConstant();
if (constant != NULL) {
if (constant->value().IsString()) {
SetValue(instr, Smi::ZoneHandle(

Powered by Google App Engine
This is Rietveld 408576698