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

Side by Side Diff: src/hydrogen-load-elimination.cc

Issue 185653004: Experimental parser: merge to r19637 (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 6 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen-instructions.cc ('k') | src/hydrogen-representation-changes.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 // The main processing of instructions. 69 // The main processing of instructions.
70 HLoadEliminationTable* Process(HInstruction* instr, Zone* zone) { 70 HLoadEliminationTable* Process(HInstruction* instr, Zone* zone) {
71 switch (instr->opcode()) { 71 switch (instr->opcode()) {
72 case HValue::kLoadNamedField: { 72 case HValue::kLoadNamedField: {
73 HLoadNamedField* l = HLoadNamedField::cast(instr); 73 HLoadNamedField* l = HLoadNamedField::cast(instr);
74 TRACE((" process L%d field %d (o%d)\n", 74 TRACE((" process L%d field %d (o%d)\n",
75 instr->id(), 75 instr->id(),
76 FieldOf(l->access()), 76 FieldOf(l->access()),
77 l->object()->ActualValue()->id())); 77 l->object()->ActualValue()->id()));
78 HValue* result = load(l); 78 HValue* result = load(l);
79 if (result != instr) { 79 if (result != instr &&
80 result->type().Equals(instr->type()) &&
81 result->representation().Equals(instr->representation())) {
80 // The load can be replaced with a previous load or a value. 82 // The load can be replaced with a previous load or a value.
81 TRACE((" replace L%d -> v%d\n", instr->id(), result->id())); 83 TRACE((" replace L%d -> v%d\n", instr->id(), result->id()));
82 instr->DeleteAndReplaceWith(result); 84 instr->DeleteAndReplaceWith(result);
83 } 85 }
84 break; 86 break;
85 } 87 }
86 case HValue::kStoreNamedField: { 88 case HValue::kStoreNamedField: {
87 HStoreNamedField* s = HStoreNamedField::cast(instr); 89 HStoreNamedField* s = HStoreNamedField::cast(instr);
88 TRACE((" process S%d field %d (o%d) = v%d\n", 90 TRACE((" process S%d field %d (o%d) = v%d\n",
89 instr->id(), 91 instr->id(),
90 FieldOf(s->access()), 92 FieldOf(s->access()),
91 s->object()->ActualValue()->id(), 93 s->object()->ActualValue()->id(),
92 s->value()->id())); 94 s->value()->id()));
93 HValue* result = store(s); 95 HValue* result = store(s);
94 if (result == NULL) { 96 if (result == NULL) {
95 // The store is redundant. Remove it. 97 // The store is redundant. Remove it.
96 TRACE((" remove S%d\n", instr->id())); 98 TRACE((" remove S%d\n", instr->id()));
97 instr->DeleteAndReplaceWith(NULL); 99 instr->DeleteAndReplaceWith(NULL);
98 } 100 }
99 break; 101 break;
100 } 102 }
103 case HValue::kTransitionElementsKind: {
104 HTransitionElementsKind* t = HTransitionElementsKind::cast(instr);
105 HValue* object = t->object()->ActualValue();
106 KillFieldInternal(object, FieldOf(JSArray::kElementsOffset), NULL);
107 KillFieldInternal(object, FieldOf(JSObject::kMapOffset), NULL);
108 break;
109 }
101 default: { 110 default: {
102 if (instr->CheckGVNFlag(kChangesInobjectFields)) { 111 if (instr->CheckChangesFlag(kInobjectFields)) {
103 TRACE((" kill-all i%d\n", instr->id())); 112 TRACE((" kill-all i%d\n", instr->id()));
104 Kill(); 113 Kill();
105 break; 114 break;
106 } 115 }
107 if (instr->CheckGVNFlag(kChangesMaps)) { 116 if (instr->CheckChangesFlag(kMaps)) {
108 TRACE((" kill-maps i%d\n", instr->id())); 117 TRACE((" kill-maps i%d\n", instr->id()));
109 KillOffset(JSObject::kMapOffset); 118 KillOffset(JSObject::kMapOffset);
110 } 119 }
111 if (instr->CheckGVNFlag(kChangesElementsKind)) { 120 if (instr->CheckChangesFlag(kElementsKind)) {
112 TRACE((" kill-elements-kind i%d\n", instr->id())); 121 TRACE((" kill-elements-kind i%d\n", instr->id()));
113 KillOffset(JSObject::kMapOffset); 122 KillOffset(JSObject::kMapOffset);
114 KillOffset(JSObject::kElementsOffset); 123 KillOffset(JSObject::kElementsOffset);
115 } 124 }
116 if (instr->CheckGVNFlag(kChangesElementsPointer)) { 125 if (instr->CheckChangesFlag(kElementsPointer)) {
117 TRACE((" kill-elements i%d\n", instr->id())); 126 TRACE((" kill-elements i%d\n", instr->id()));
118 KillOffset(JSObject::kElementsOffset); 127 KillOffset(JSObject::kElementsOffset);
119 } 128 }
120 if (instr->CheckGVNFlag(kChangesOsrEntries)) { 129 if (instr->CheckChangesFlag(kOsrEntries)) {
121 TRACE((" kill-osr i%d\n", instr->id())); 130 TRACE((" kill-osr i%d\n", instr->id()));
122 Kill(); 131 Kill();
123 } 132 }
124 } 133 }
125 // Improvements possible: 134 // Improvements possible:
126 // - learn from HCheckMaps for field 0 135 // - learn from HCheckMaps for field 0
127 // - remove unobservable stores (write-after-write) 136 // - remove unobservable stores (write-after-write)
128 // - track cells 137 // - track cells
129 // - track globals 138 // - track globals
130 // - track roots 139 // - track roots
131 } 140 }
132 return this; 141 return this;
133 } 142 }
134 143
135 // Support for global analysis with HFlowEngine: Copy state to sucessor block. 144 // Support for global analysis with HFlowEngine: Merge given state with
136 HLoadEliminationTable* Copy(HBasicBlock* succ, Zone* zone) { 145 // the other incoming state.
146 static HLoadEliminationTable* Merge(HLoadEliminationTable* succ_state,
147 HBasicBlock* succ_block,
148 HLoadEliminationTable* pred_state,
149 HBasicBlock* pred_block,
150 Zone* zone) {
151 ASSERT(pred_state != NULL);
152 if (succ_state == NULL) {
153 return pred_state->Copy(succ_block, pred_block, zone);
154 } else {
155 return succ_state->Merge(succ_block, pred_state, pred_block, zone);
156 }
157 }
158
159 // Support for global analysis with HFlowEngine: Given state merged with all
160 // the other incoming states, prepare it for use.
161 static HLoadEliminationTable* Finish(HLoadEliminationTable* state,
162 HBasicBlock* block,
163 Zone* zone) {
164 ASSERT(state != NULL);
165 return state;
166 }
167
168 private:
169 // Copy state to successor block.
170 HLoadEliminationTable* Copy(HBasicBlock* succ, HBasicBlock* from_block,
171 Zone* zone) {
137 HLoadEliminationTable* copy = 172 HLoadEliminationTable* copy =
138 new(zone) HLoadEliminationTable(zone, aliasing_); 173 new(zone) HLoadEliminationTable(zone, aliasing_);
139 copy->EnsureFields(fields_.length()); 174 copy->EnsureFields(fields_.length());
140 for (int i = 0; i < fields_.length(); i++) { 175 for (int i = 0; i < fields_.length(); i++) {
141 copy->fields_[i] = fields_[i]->Copy(zone); 176 copy->fields_[i] = fields_[i]->Copy(zone);
142 } 177 }
143 if (FLAG_trace_load_elimination) { 178 if (FLAG_trace_load_elimination) {
144 TRACE((" copy-to B%d\n", succ->block_id())); 179 TRACE((" copy-to B%d\n", succ->block_id()));
145 copy->Print(); 180 copy->Print();
146 } 181 }
147 return copy; 182 return copy;
148 } 183 }
149 184
150 // Support for global analysis with HFlowEngine: Merge this state with 185 // Merge this state with the other incoming state.
151 // the other incoming state. 186 HLoadEliminationTable* Merge(HBasicBlock* succ, HLoadEliminationTable* that,
152 HLoadEliminationTable* Merge(HBasicBlock* succ, 187 HBasicBlock* that_block, Zone* zone) {
153 HLoadEliminationTable* that, Zone* zone) {
154 if (that->fields_.length() < fields_.length()) { 188 if (that->fields_.length() < fields_.length()) {
155 // Drop fields not in the other table. 189 // Drop fields not in the other table.
156 fields_.Rewind(that->fields_.length()); 190 fields_.Rewind(that->fields_.length());
157 } 191 }
158 for (int i = 0; i < fields_.length(); i++) { 192 for (int i = 0; i < fields_.length(); i++) {
159 // Merge the field approximations for like fields. 193 // Merge the field approximations for like fields.
160 HFieldApproximation* approx = fields_[i]; 194 HFieldApproximation* approx = fields_[i];
161 HFieldApproximation* prev = NULL; 195 HFieldApproximation* prev = NULL;
162 while (approx != NULL) { 196 while (approx != NULL) {
163 // TODO(titzer): Merging is O(N * M); sort? 197 // TODO(titzer): Merging is O(N * M); sort?
164 HFieldApproximation* other = that->Find(approx->object_, i); 198 HFieldApproximation* other = that->Find(approx->object_, i);
165 if (other == NULL || !Equal(approx->last_value_, other->last_value_)) { 199 if (other == NULL || !Equal(approx->last_value_, other->last_value_)) {
166 // Kill an entry that doesn't agree with the other value. 200 // Kill an entry that doesn't agree with the other value.
167 if (prev != NULL) { 201 if (prev != NULL) {
168 prev->next_ = approx->next_; 202 prev->next_ = approx->next_;
169 } else { 203 } else {
170 fields_[i] = approx->next_; 204 fields_[i] = approx->next_;
171 } 205 }
172 approx = approx->next_; 206 approx = approx->next_;
173 continue; 207 continue;
174 } 208 }
175 prev = approx; 209 prev = approx;
176 approx = approx->next_; 210 approx = approx->next_;
177 } 211 }
178 } 212 }
213 if (FLAG_trace_load_elimination) {
214 TRACE((" merge-to B%d\n", succ->block_id()));
215 Print();
216 }
179 return this; 217 return this;
180 } 218 }
181 219
182 friend class HLoadEliminationEffects; // Calls Kill() and others. 220 friend class HLoadEliminationEffects; // Calls Kill() and others.
183 friend class HLoadEliminationPhase; 221 friend class HLoadEliminationPhase;
184 222
185 private: 223 private:
186 // Process a load instruction, updating internal table state. If a previous 224 // Process a load instruction, updating internal table state. If a previous
187 // load or store for this object and field exists, return the new value with 225 // load or store for this object and field exists, return the new value with
188 // which the load should be replaced. Otherwise, return {instr}. 226 // which the load should be replaced. Otherwise, return {instr}.
189 HValue* load(HLoadNamedField* instr) { 227 HValue* load(HLoadNamedField* instr) {
228 // There must be no loads from non observable in-object properties.
229 ASSERT(!instr->access().IsInobject() ||
230 instr->access().existing_inobject_property());
231
190 int field = FieldOf(instr->access()); 232 int field = FieldOf(instr->access());
191 if (field < 0) return instr; 233 if (field < 0) return instr;
192 234
193 HValue* object = instr->object()->ActualValue(); 235 HValue* object = instr->object()->ActualValue();
194 HFieldApproximation* approx = FindOrCreate(object, field); 236 HFieldApproximation* approx = FindOrCreate(object, field);
195 237
196 if (approx->last_value_ == NULL) { 238 if (approx->last_value_ == NULL) {
197 // Load is not redundant. Fill out a new entry. 239 // Load is not redundant. Fill out a new entry.
198 approx->last_value_ = instr; 240 approx->last_value_ = instr;
199 return instr; 241 return instr;
200 } else { 242 } else if (approx->last_value_->block()->EqualToOrDominates(
243 instr->block())) {
201 // Eliminate the load. Reuse previously stored value or load instruction. 244 // Eliminate the load. Reuse previously stored value or load instruction.
202 return approx->last_value_; 245 return approx->last_value_;
246 } else {
247 return instr;
203 } 248 }
204 } 249 }
205 250
206 // Process a store instruction, updating internal table state. If a previous 251 // Process a store instruction, updating internal table state. If a previous
207 // store to the same object and field makes this store redundant (e.g. because 252 // store to the same object and field makes this store redundant (e.g. because
208 // the stored values are the same), return NULL indicating that this store 253 // the stored values are the same), return NULL indicating that this store
209 // instruction is redundant. Otherwise, return {instr}. 254 // instruction is redundant. Otherwise, return {instr}.
210 HValue* store(HStoreNamedField* instr) { 255 HValue* store(HStoreNamedField* instr) {
256 if (instr->access().IsInobject() &&
257 !instr->access().existing_inobject_property()) {
258 TRACE((" skipping non existing property initialization store\n"));
259 return instr;
260 }
261
211 int field = FieldOf(instr->access()); 262 int field = FieldOf(instr->access());
212 if (field < 0) return KillIfMisaligned(instr); 263 if (field < 0) return KillIfMisaligned(instr);
213 264
214 HValue* object = instr->object()->ActualValue(); 265 HValue* object = instr->object()->ActualValue();
215 HValue* value = instr->value(); 266 HValue* value = instr->value();
216 267
217 if (instr->has_transition()) { 268 if (instr->has_transition()) {
218 // A transition introduces a new field and alters the map of the object. 269 // A transition introduces a new field and alters the map of the object.
219 // Since the field in the object is new, it cannot alias existing entries. 270 // Since the field in the object is new, it cannot alias existing entries.
220 // TODO(titzer): introduce a constant for the new map and remember it. 271 // TODO(titzer): introduce a constant for the new map and remember it.
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 Zone* zone_; 455 Zone* zone_;
405 ZoneList<HFieldApproximation*> fields_; 456 ZoneList<HFieldApproximation*> fields_;
406 HAliasAnalyzer* aliasing_; 457 HAliasAnalyzer* aliasing_;
407 }; 458 };
408 459
409 460
410 // Support for HFlowEngine: collect store effects within loops. 461 // Support for HFlowEngine: collect store effects within loops.
411 class HLoadEliminationEffects : public ZoneObject { 462 class HLoadEliminationEffects : public ZoneObject {
412 public: 463 public:
413 explicit HLoadEliminationEffects(Zone* zone) 464 explicit HLoadEliminationEffects(Zone* zone)
414 : zone_(zone), 465 : zone_(zone), stores_(5, zone) { }
415 maps_stored_(false),
416 fields_stored_(false),
417 elements_stored_(false),
418 stores_(5, zone) { }
419 466
420 inline bool Disabled() { 467 inline bool Disabled() {
421 return false; // Effects are _not_ disabled. 468 return false; // Effects are _not_ disabled.
422 } 469 }
423 470
424 // Process a possibly side-effecting instruction. 471 // Process a possibly side-effecting instruction.
425 void Process(HInstruction* instr, Zone* zone) { 472 void Process(HInstruction* instr, Zone* zone) {
426 switch (instr->opcode()) { 473 if (instr->IsStoreNamedField()) {
427 case HValue::kStoreNamedField: { 474 stores_.Add(HStoreNamedField::cast(instr), zone_);
428 stores_.Add(HStoreNamedField::cast(instr), zone_); 475 } else {
429 break; 476 flags_.Add(instr->ChangesFlags());
430 }
431 case HValue::kOsrEntry: {
432 // Kill everything. Loads must not be hoisted past the OSR entry.
433 maps_stored_ = true;
434 fields_stored_ = true;
435 elements_stored_ = true;
436 }
437 default: {
438 fields_stored_ |= instr->CheckGVNFlag(kChangesInobjectFields);
439 maps_stored_ |= instr->CheckGVNFlag(kChangesMaps);
440 maps_stored_ |= instr->CheckGVNFlag(kChangesElementsKind);
441 elements_stored_ |= instr->CheckGVNFlag(kChangesElementsKind);
442 elements_stored_ |= instr->CheckGVNFlag(kChangesElementsPointer);
443 }
444 } 477 }
445 } 478 }
446 479
447 // Apply these effects to the given load elimination table. 480 // Apply these effects to the given load elimination table.
448 void Apply(HLoadEliminationTable* table) { 481 void Apply(HLoadEliminationTable* table) {
449 if (fields_stored_) { 482 // Loads must not be hoisted past the OSR entry, therefore we kill
483 // everything if we see an OSR entry.
484 if (flags_.Contains(kInobjectFields) || flags_.Contains(kOsrEntries)) {
450 table->Kill(); 485 table->Kill();
451 return; 486 return;
452 } 487 }
453 if (maps_stored_) { 488 if (flags_.Contains(kElementsKind) || flags_.Contains(kMaps)) {
454 table->KillOffset(JSObject::kMapOffset); 489 table->KillOffset(JSObject::kMapOffset);
455 } 490 }
456 if (elements_stored_) { 491 if (flags_.Contains(kElementsKind) || flags_.Contains(kElementsPointer)) {
457 table->KillOffset(JSObject::kElementsOffset); 492 table->KillOffset(JSObject::kElementsOffset);
458 } 493 }
459 494
460 // Kill non-agreeing fields for each store contained in these effects. 495 // Kill non-agreeing fields for each store contained in these effects.
461 for (int i = 0; i < stores_.length(); i++) { 496 for (int i = 0; i < stores_.length(); i++) {
462 table->KillStore(stores_[i]); 497 table->KillStore(stores_[i]);
463 } 498 }
464 } 499 }
465 500
466 // Union these effects with the other effects. 501 // Union these effects with the other effects.
467 void Union(HLoadEliminationEffects* that, Zone* zone) { 502 void Union(HLoadEliminationEffects* that, Zone* zone) {
468 maps_stored_ |= that->maps_stored_; 503 flags_.Add(that->flags_);
469 fields_stored_ |= that->fields_stored_;
470 elements_stored_ |= that->elements_stored_;
471 for (int i = 0; i < that->stores_.length(); i++) { 504 for (int i = 0; i < that->stores_.length(); i++) {
472 stores_.Add(that->stores_[i], zone); 505 stores_.Add(that->stores_[i], zone);
473 } 506 }
474 } 507 }
475 508
476 private: 509 private:
477 Zone* zone_; 510 Zone* zone_;
478 bool maps_stored_ : 1; 511 GVNFlagSet flags_;
479 bool fields_stored_ : 1;
480 bool elements_stored_ : 1;
481 ZoneList<HStoreNamedField*> stores_; 512 ZoneList<HStoreNamedField*> stores_;
482 }; 513 };
483 514
484 515
485 // The main routine of the analysis phase. Use the HFlowEngine for either a 516 // The main routine of the analysis phase. Use the HFlowEngine for either a
486 // local or a global analysis. 517 // local or a global analysis.
487 void HLoadEliminationPhase::Run() { 518 void HLoadEliminationPhase::Run() {
488 HFlowEngine<HLoadEliminationTable, HLoadEliminationEffects> 519 HFlowEngine<HLoadEliminationTable, HLoadEliminationEffects>
489 engine(graph(), zone()); 520 engine(graph(), zone());
490 HAliasAnalyzer aliasing; 521 HAliasAnalyzer aliasing;
491 HLoadEliminationTable* table = 522 HLoadEliminationTable* table =
492 new(zone()) HLoadEliminationTable(zone(), &aliasing); 523 new(zone()) HLoadEliminationTable(zone(), &aliasing);
493 524
494 if (GLOBAL) { 525 if (GLOBAL) {
495 // Perform a global analysis. 526 // Perform a global analysis.
496 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), table); 527 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), table);
497 } else { 528 } else {
498 // Perform only local analysis. 529 // Perform only local analysis.
499 for (int i = 0; i < graph()->blocks()->length(); i++) { 530 for (int i = 0; i < graph()->blocks()->length(); i++) {
500 table->Kill(); 531 table->Kill();
501 engine.AnalyzeOneBlock(graph()->blocks()->at(i), table); 532 engine.AnalyzeOneBlock(graph()->blocks()->at(i), table);
502 } 533 }
503 } 534 }
504 } 535 }
505 536
506 } } // namespace v8::internal 537 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen-instructions.cc ('k') | src/hydrogen-representation-changes.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698