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

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

Issue 141653009: Check elimination improvement: propagation of state through phis is supported, CheckMap narrowing i… (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review notes applied Created 6 years, 10 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.cc ('k') | src/hydrogen-instructions.h » ('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 30 matching lines...) Expand all
41 // For code de-uglification. 41 // For code de-uglification.
42 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x 42 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x
43 43
44 namespace v8 { 44 namespace v8 {
45 namespace internal { 45 namespace internal {
46 46
47 typedef UniqueSet<Map>* MapSet; 47 typedef UniqueSet<Map>* MapSet;
48 48
49 struct HCheckTableEntry { 49 struct HCheckTableEntry {
50 HValue* object_; // The object being approximated. NULL => invalid entry. 50 HValue* object_; // The object being approximated. NULL => invalid entry.
51 HValue* check_; // The last check instruction. 51 HInstruction* check_; // The last check instruction.
52 MapSet maps_; // The set of known maps for the object. 52 MapSet maps_; // The set of known maps for the object.
53 }; 53 };
54 54
55 55
56 // The main datastructure used during check elimination, which stores a 56 // The main data structure used during check elimination, which stores a
57 // set of known maps for each object. 57 // set of known maps for each object.
58 class HCheckTable : public ZoneObject { 58 class HCheckTable : public ZoneObject {
59 public: 59 public:
60 static const int kMaxTrackedObjects = 10; 60 static const int kMaxTrackedObjects = 10;
61 61
62 explicit HCheckTable(HCheckEliminationPhase* phase) 62 explicit HCheckTable(HCheckEliminationPhase* phase)
63 : phase_(phase), 63 : phase_(phase),
64 cursor_(0), 64 cursor_(0),
65 size_(0) { 65 size_(0) {
66 } 66 }
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 HCheckTableEntry* old_entry = &entries_[i]; 123 HCheckTableEntry* old_entry = &entries_[i];
124 HCheckTableEntry* new_entry = &copy->entries_[i]; 124 HCheckTableEntry* new_entry = &copy->entries_[i];
125 // TODO(titzer): keep the check if this block dominates the successor? 125 // TODO(titzer): keep the check if this block dominates the successor?
126 new_entry->object_ = old_entry->object_; 126 new_entry->object_ = old_entry->object_;
127 new_entry->check_ = NULL; 127 new_entry->check_ = NULL;
128 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone()); 128 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone());
129 } 129 }
130 copy->cursor_ = cursor_; 130 copy->cursor_ = cursor_;
131 copy->size_ = size_; 131 copy->size_ = size_;
132 132
133 copy->InheritPhiOperands(succ, this, from_block, COPY, zone);
134
133 // Branch-sensitive analysis for certain comparisons may add more facts 135 // Branch-sensitive analysis for certain comparisons may add more facts
134 // to the state for the successor on the true branch. 136 // to the state for the successor on the true branch.
135 bool learned = false; 137 bool learned = false;
136 HControlInstruction* end = succ->predecessors()->at(0)->end(); 138 HControlInstruction* end = succ->predecessors()->at(0)->end();
137 if (succ->predecessors()->length() == 1 && end->SuccessorAt(0) == succ) { 139 if (succ->predecessors()->length() == 1 && end->SuccessorAt(0) == succ) {
138 if (end->IsCompareMap()) { 140 if (end->IsCompareMap()) {
139 // Learn on the true branch of if(CompareMap(x)). 141 // Learn on the true branch of if(CompareMap(x)).
140 HCompareMap* cmp = HCompareMap::cast(end); 142 HCompareMap* cmp = HCompareMap::cast(end);
141 HValue* object = cmp->value()->ActualValue(); 143 HValue* object = cmp->value()->ActualValue();
142 HCheckTableEntry* entry = copy->Find(object); 144 HCheckTableEntry* entry = copy->Find(object);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 succ->block_id(), 179 succ->block_id(),
178 learned ? "learned" : "copied", 180 learned ? "learned" : "copied",
179 from_block->block_id()); 181 from_block->block_id());
180 copy->Print(); 182 copy->Print();
181 } 183 }
182 184
183 return copy; 185 return copy;
184 } 186 }
185 187
186 // Global analysis: Merge this state with the other incoming state. 188 // Global analysis: Merge this state with the other incoming state.
187 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that, 189 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that,
titzer 2014/02/04 13:12:26 We should rename "that" to be "pred", to be more c
Igor Sheludko 2014/02/05 11:28:01 Done.
titzer 2014/02/05 11:47:46 To be clearer: "that_block" to "pred_block"
Igor Sheludko 2014/02/05 12:26:10 Done.
188 HBasicBlock* that_block, Zone* zone) { 190 HBasicBlock* that_block, Zone* zone) {
189 if (that_block->IsReachable()) { 191 if (that_block->IsReachable()) {
190 if (that->size_ == 0) { 192 if (that->size_ == 0) {
191 // If the other state is empty, simply reset. 193 // If the other state is empty, simply reset.
192 size_ = 0; 194 size_ = 0;
193 cursor_ = 0; 195 cursor_ = 0;
194 } else { 196 } else {
197 InheritPhiOperands(succ, that, that_block, MERGE, zone);
titzer 2014/02/04 13:12:26 Why don't you process the phis after first merging
Igor Sheludko 2014/02/05 11:28:01 Good idea!
198
195 bool compact = false; 199 bool compact = false;
196 for (int i = 0; i < size_; i++) { 200 for (int i = 0; i < size_; i++) {
197 HCheckTableEntry* this_entry = &entries_[i]; 201 HCheckTableEntry* this_entry = &entries_[i];
titzer 2014/02/04 13:12:26 Using the above suggestion, you can simply retain
Igor Sheludko 2014/02/05 11:28:01 Done.
198 HCheckTableEntry* that_entry = that->Find(this_entry->object_); 202 HCheckTableEntry* that_entry = that->Find(this_entry->object_);
203 // Keep those phis in the table that dominate succ block.
199 if (that_entry == NULL) { 204 if (that_entry == NULL) {
200 this_entry->object_ = NULL; 205 if (!this_entry->object_->IsPhi() ||
201 compact = true; 206 !this_entry->object_->block()->EqualToOrDominates(succ)) {
207 this_entry->object_ = NULL;
208 compact = true;
209 }
202 } else { 210 } else {
203 this_entry->maps_ = 211 this_entry->maps_ =
204 this_entry->maps_->Union(that_entry->maps_, phase_->zone()); 212 this_entry->maps_->Union(that_entry->maps_, phase_->zone());
205 if (this_entry->check_ != that_entry->check_) { 213 if (this_entry->check_ != that_entry->check_) {
206 this_entry->check_ = NULL; 214 this_entry->check_ = NULL;
207 } 215 }
208 ASSERT(this_entry->maps_->size() > 0); 216 ASSERT(this_entry->maps_->size() > 0);
209 } 217 }
210 } 218 }
211 if (compact) Compact(); 219 if (compact) Compact();
212 } 220 }
213 } 221 }
214 if (FLAG_trace_check_elimination) { 222 if (FLAG_trace_check_elimination) {
215 PrintF("B%d checkmaps-table merged with B%d table:\n", 223 PrintF("B%d checkmaps-table merged with B%d table:\n",
216 succ->block_id(), that_block->block_id()); 224 succ->block_id(), that_block->block_id());
217 Print(); 225 Print();
218 } 226 }
219 return this; 227 return this;
220 } 228 }
221 229
230 enum InheritPhiOperandsMode { COPY, MERGE };
231 void InheritPhiOperands(HBasicBlock* succ, HCheckTable* that,
232 HBasicBlock* that_block, InheritPhiOperandsMode mode,
233 Zone* zone) {
234 if (succ->predecessors()->length() == 1) return;
titzer 2014/02/04 13:12:26 I think you want to check succ->phis()->length() =
Igor Sheludko 2014/02/05 11:28:01 Done.
235
236 int pred_index = succ->PredecessorIndexOf(that_block);
237
238 for (int i = 0; i < that->size_; i++) {
239 HCheckTableEntry* that_entry = &that->entries_[i];
240 if (that_entry->object_ != NULL) {
241 HPhi* phi = NULL;
242 for (int phi_index = 0;
243 phi_index < succ->phis()->length();
244 ++phi_index) {
245 HPhi* tmp_phi = succ->phis()->at(phi_index);
246 if (tmp_phi->OperandAt(pred_index) == that_entry->object_) {
247 phi = tmp_phi;
248 break;
249 }
250 }
251
252 if (phi != NULL) {
253 // Found a |phi| with operand equal to |that_entry->object_|.
254 HCheckTableEntry* phi_entry = (mode == MERGE) ? Find(phi) : NULL;
255 if (phi_entry == NULL) {
256 // Create an entry for a phi in the table.
257 Insert(phi, NULL, that_entry->maps_);
258 } else {
259 phi_entry->maps_ =
260 phi_entry->maps_->Union(that_entry->maps_, phase_->zone());
261 }
262 }
263 }
264 }
265 }
266
222 void ReduceCheckMaps(HCheckMaps* instr) { 267 void ReduceCheckMaps(HCheckMaps* instr) {
223 HValue* object = instr->value()->ActualValue(); 268 HValue* object = instr->value()->ActualValue();
224 HCheckTableEntry* entry = Find(object); 269 HCheckTableEntry* entry = Find(object);
225 if (entry != NULL) { 270 if (entry != NULL) {
226 // entry found; 271 // entry found;
227 MapSet a = entry->maps_; 272 MapSet a = entry->maps_;
228 MapSet i = instr->map_set().Copy(phase_->zone()); 273 MapSet i = instr->map_set().Copy(phase_->zone());
229 if (a->IsSubset(i)) { 274 if (a->IsSubset(i)) {
230 // The first check is more strict; the second is redundant. 275 // The first check is more strict; the second is redundant.
231 if (entry->check_ != NULL) { 276 if (entry->check_ != NULL) {
232 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", 277 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
233 instr->id(), instr->block()->block_id(), entry->check_->id())); 278 instr->id(), instr->block()->block_id(), entry->check_->id()));
234 instr->DeleteAndReplaceWith(entry->check_); 279 instr->DeleteAndReplaceWith(entry->check_);
235 INC_STAT(redundant_); 280 INC_STAT(redundant_);
236 } else { 281 } else {
237 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n", 282 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n",
238 instr->id(), instr->block()->block_id())); 283 instr->id(), instr->block()->block_id()));
239 // Mark check as dead but leave it in the graph as a checkpoint for 284 // Mark check as dead but leave it in the graph as a checkpoint for
240 // subsequent checks. 285 // subsequent checks.
241 instr->SetFlag(HValue::kIsDead); 286 instr->SetFlag(HValue::kIsDead);
242 entry->check_ = instr; 287 entry->check_ = instr;
243 INC_STAT(removed_); 288 INC_STAT(removed_);
244 } 289 }
245 return; 290 return;
246 } 291 }
247 i = i->Intersect(a, phase_->zone()); 292 MapSet intersection = i->Intersect(a, phase_->zone());
248 if (i->size() == 0) { 293 if (intersection->size() == 0) {
249 // Intersection is empty; probably megamorphic, which is likely to 294 // Intersection is empty; probably megamorphic, which is likely to
250 // deopt anyway, so just leave things as they are. 295 // deopt anyway, so just leave things as they are.
251 INC_STAT(empty_); 296 INC_STAT(empty_);
252 } else { 297 } else {
253 // TODO(titzer): replace the first check with a more strict check 298 // Update set of maps in the entry.
254 INC_STAT(narrowed_); 299 entry->maps_ = intersection;
300 if (intersection->size() != i->size()) {
301 // Narrow set of maps in the second check maps instruction.
302 HGraph* graph = instr->block()->graph();
303 HCheckMaps* new_check_maps =
304 HCheckMaps::New(graph->zone(), NULL, instr->value(),
305 intersection, instr->typecheck());
306 if (entry->check_ != NULL &&
307 entry->check_->block() == instr->block()) {
308 // There is a check in the same block so replace it with a more
309 // strict check and eliminate the second check entirely.
310 new_check_maps->InsertBefore(entry->check_);
311 entry->check_->DeleteAndReplaceWith(new_check_maps);
312 TRACE(("Check #%d narrowed to #%d\n",
313 entry->check_->id(), new_check_maps->id()));
314
315 } else {
316 new_check_maps->InsertBefore(instr);
317 }
318 TRACE(("CheckMaps #%d for #%d narrowed to #%d:\n",
319 instr->id(), instr->value()->id(), new_check_maps->id()));
320 instr->DeleteAndReplaceWith(new_check_maps);
321 entry->check_ = new_check_maps;
322
323 if (FLAG_trace_check_elimination) {
324 Print();
325 }
326 INC_STAT(narrowed_);
327 }
255 } 328 }
256 } else { 329 } else {
257 // No entry; insert a new one. 330 // No entry; insert a new one.
258 Insert(object, instr, instr->map_set().Copy(phase_->zone())); 331 Insert(object, instr, instr->map_set().Copy(phase_->zone()));
259 } 332 }
260 } 333 }
261 334
262 void ReduceCheckValue(HCheckValue* instr) { 335 void ReduceCheckValue(HCheckValue* instr) {
263 // Canonicalize HCheckValues; they might have their values load-eliminated. 336 // Canonicalize HCheckValues; they might have their values load-eliminated.
264 HValue* value = instr->Canonicalize(); 337 HValue* value = instr->Canonicalize();
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 PRINT_STAT(removed_cho); 653 PRINT_STAT(removed_cho);
581 PRINT_STAT(narrowed); 654 PRINT_STAT(narrowed);
582 PRINT_STAT(loads); 655 PRINT_STAT(loads);
583 PRINT_STAT(empty); 656 PRINT_STAT(empty);
584 PRINT_STAT(compares_true); 657 PRINT_STAT(compares_true);
585 PRINT_STAT(compares_false); 658 PRINT_STAT(compares_false);
586 PRINT_STAT(transitions); 659 PRINT_STAT(transitions);
587 } 660 }
588 661
589 } } // namespace v8::internal 662 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.cc ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698