Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph.h" | 5 #include "vm/flow_graph.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 Instruction* previous = entry; | 57 Instruction* previous = entry; |
| 58 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 58 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 59 Instruction* current = it.Current(); | 59 Instruction* current = it.Current(); |
| 60 current->set_previous(previous); | 60 current->set_previous(previous); |
| 61 previous = current; | 61 previous = current; |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 } | 64 } |
| 65 | 65 |
| 66 | 66 |
| 67 #ifdef DEBUG | |
| 68 // Helper class to check consistency of the use list construction. Clears all | |
| 69 // use-list data in one pass which is then used for assertions when building the | |
| 70 // use lists. | |
| 71 class DefUseCleanup : public FlowGraphVisitor { | |
| 72 public: | |
| 73 explicit DefUseCleanup(FlowGraph* flow_graph) | |
| 74 : FlowGraphVisitor(flow_graph->preorder()) { } | |
| 75 void CleanupInstruction(Instruction* instr) { | |
| 76 JoinEntryInstr* join = instr->AsJoinEntry(); | |
| 77 if (join != NULL && join->phis() != NULL) { | |
| 78 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
| 79 PhiInstr* phi = (*join->phis())[i]; | |
| 80 if (phi != NULL) CleanupInstruction(phi); | |
| 81 } | |
| 82 } | |
| 83 Definition* defn = instr->AsDefinition(); | |
| 84 if (defn != NULL) { | |
| 85 defn->set_instr_use_list(NULL); | |
| 86 defn->set_env_use_list(NULL); | |
| 87 } | |
| 88 for (intptr_t i = 0; i < instr->InputCount(); ++i) { | |
| 89 UseVal* use = instr->InputAt(i)->AsUse(); | |
| 90 if (use == NULL) continue; | |
| 91 use->set_instruction(NULL); | |
| 92 use->set_use_index(-1); | |
| 93 use->set_next_use(NULL); | |
| 94 } | |
| 95 if (instr->env() != NULL) { | |
| 96 for (intptr_t i = 0; i < instr->env()->values().length(); ++i) { | |
| 97 UseVal* use = instr->env()->values()[i]->AsUse(); | |
| 98 if (use == NULL) continue; | |
| 99 use->set_instruction(NULL); | |
| 100 use->set_use_index(-1); | |
| 101 use->set_next_use(NULL); | |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 #define DEFINE_VISIT(type) \ | |
| 106 virtual void Visit##type(type##Instr* instr) { CleanupInstruction(instr); } | |
| 107 FOR_EACH_INSTRUCTION(DEFINE_VISIT) | |
| 108 #undef DEFINE_VISIT | |
| 109 }; | |
| 110 #endif // DEBUG | |
| 111 | |
| 112 | |
| 113 static void ClearUseLists(Definition* defn) { | |
| 114 ASSERT(defn != NULL); | |
| 115 ASSERT(defn->instr_use_list() == NULL); | |
| 116 ASSERT(defn->env_use_list() == NULL); | |
| 117 defn->set_instr_use_list(NULL); | |
| 118 defn->set_env_use_list(NULL); | |
| 119 } | |
| 120 | |
| 121 | |
| 122 static void ComputeInstructionUses(Instruction* instr) { | |
| 123 ASSERT(instr != NULL); | |
| 124 for (intptr_t i = 0; i < instr->InputCount(); ++i) { | |
| 125 UseVal* use = instr->InputAt(i)->AsUse(); | |
| 126 if (use == NULL) continue; | |
| 127 ASSERT(use->instruction() == NULL); | |
| 128 ASSERT(use->use_index() == -1); | |
| 129 ASSERT(use->next_use() == NULL); | |
| 130 use->set_instruction(instr); | |
| 131 use->set_use_index(i); | |
| 132 use->set_next_use(use->definition()->instr_use_list()); | |
| 133 use->definition()->set_instr_use_list(use); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 | |
| 138 static void ComputeEnvironmentUses(Instruction* instr) { | |
| 139 ASSERT(instr != NULL); | |
| 140 if (instr->env() == NULL) return; | |
| 141 for (intptr_t i = 0; i < instr->env()->values().length(); ++i) { | |
| 142 UseVal* use = instr->env()->values()[i]->AsUse(); | |
| 143 if (use == NULL) continue; | |
| 144 ASSERT(use->instruction() == NULL); | |
| 145 ASSERT(use->use_index() == -1); | |
| 146 ASSERT(use->next_use() == NULL); | |
| 147 use->set_instruction(instr); | |
|
Vyacheslav Egorov (Google)
2012/08/23 13:51:10
This code for placing use into the list is duplica
zerny-google
2012/08/23 16:11:20
Done. (Added AddToInputUse/AddToEnvUse on UseVal)
| |
| 148 use->set_use_index(i); | |
| 149 use->set_next_use(use->definition()->env_use_list()); | |
| 150 use->definition()->set_env_use_list(use); | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 | |
| 155 static void ComputeUsesInBlock(BlockEntryInstr* block) { | |
|
Kevin Millikin (Google)
2012/08/23 13:35:34
Name is not quite right, because it computes uses
zerny-google
2012/08/23 16:11:20
Done.
| |
| 156 // Clear phi definitions. | |
| 157 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 158 if (join != NULL && join->phis() != NULL) { | |
| 159 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
| 160 PhiInstr* phi = (*join->phis())[i]; | |
| 161 if (phi != NULL) ClearUseLists(phi); | |
| 162 } | |
| 163 } | |
| 164 // Compute uses on normal instructions. | |
| 165 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 166 Instruction* instr = it.Current(); | |
| 167 if (instr->IsDefinition()) ClearUseLists(instr->AsDefinition()); | |
| 168 ComputeInstructionUses(instr); | |
|
Kevin Millikin (Google)
2012/08/23 13:35:34
Name is not quite right. It sounds like it's comp
zerny-google
2012/08/23 16:11:20
Yes. Similar to this, instr_use has been replaced
| |
| 169 ComputeEnvironmentUses(instr); | |
| 170 } | |
| 171 // Compute recursively on dominated blocks. | |
| 172 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | |
| 173 ComputeUsesInBlock(block->dominated_blocks()[i]); | |
| 174 } | |
| 175 // Add phi uses on back-edges. | |
|
Kevin Millikin (Google)
2012/08/23 13:35:34
Not just back edges, all successor edges.
| |
| 176 if (block->last_instruction()->SuccessorCount() == 1 && | |
| 177 block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { | |
| 178 JoinEntryInstr* join = | |
| 179 block->last_instruction()->SuccessorAt(0)->AsJoinEntry(); | |
| 180 intptr_t pred_index = join->IndexOfPredecessor(block); | |
| 181 ASSERT(pred_index >= 0); | |
| 182 if (join->phis() != NULL) { | |
| 183 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
| 184 PhiInstr* phi = (*join->phis())[i]; | |
| 185 if (phi == NULL) continue; | |
| 186 UseVal* use = phi->InputAt(pred_index)->AsUse(); | |
| 187 if (use == NULL) continue; | |
| 188 ASSERT(use->instruction() == NULL); | |
| 189 ASSERT(use->use_index() == -1); | |
| 190 ASSERT(use->next_use() == NULL); | |
| 191 use->set_instruction(phi); | |
| 192 use->set_use_index(pred_index); | |
| 193 use->set_next_use(use->definition()->instr_use_list()); | |
| 194 use->definition()->set_instr_use_list(use); | |
| 195 } | |
| 196 } | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 | |
| 201 bool FlowGraph::ComputeUseLists() { | |
| 202 #ifdef DEBUG | |
| 203 DefUseCleanup cleanup(this); | |
|
Kevin Millikin (Google)
2012/08/23 13:35:34
I don't really like the verification. It's a bit
zerny-google
2012/08/23 16:11:20
I can pull this out, but if so, it is really hard
| |
| 204 cleanup.VisitBlocks(); | |
| 205 #endif // DEBUG | |
| 206 ComputeUsesInBlock(graph_entry_); | |
| 207 return true; | |
|
Vyacheslav Egorov (Google)
2012/08/23 13:51:10
what is the reason to have return values which is
| |
| 208 } | |
| 209 | |
| 210 | |
| 67 void FlowGraph::ComputeSSA() { | 211 void FlowGraph::ComputeSSA() { |
| 68 GrowableArray<BitVector*> dominance_frontier; | 212 GrowableArray<BitVector*> dominance_frontier; |
| 69 ComputeDominators(&preorder_, &parent_, &dominance_frontier); | 213 ComputeDominators(&preorder_, &parent_, &dominance_frontier); |
| 70 InsertPhis(preorder_, assigned_vars_, dominance_frontier); | 214 InsertPhis(preorder_, assigned_vars_, dominance_frontier); |
| 71 GrowableArray<PhiInstr*> live_phis; | 215 GrowableArray<PhiInstr*> live_phis; |
| 72 // Rename uses to reference inserted phis where appropriate. | 216 // Rename uses to reference inserted phis where appropriate. |
| 73 // Collect phis that reach a non-environment use. | 217 // Collect phis that reach a non-environment use. |
| 74 Rename(&live_phis); | 218 Rename(&live_phis); |
| 75 // Propagate alive mark transitively from alive phis. | 219 // Propagate alive mark transitively from alive phis. |
| 76 MarkLivePhis(&live_phis); | 220 MarkLivePhis(&live_phis); |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 // Update expression stack. | 479 // Update expression stack. |
| 336 ASSERT(env->length() > variable_count()); | 480 ASSERT(env->length() > variable_count()); |
| 337 | 481 |
| 338 Definition* input_defn = env->Last(); | 482 Definition* input_defn = env->Last(); |
| 339 env->RemoveLast(); | 483 env->RemoveLast(); |
| 340 | 484 |
| 341 BindInstr* as_bind = v->AsUse()->definition()->AsBind(); | 485 BindInstr* as_bind = v->AsUse()->definition()->AsBind(); |
| 342 if ((as_bind != NULL) && | 486 if ((as_bind != NULL) && |
| 343 (as_bind->computation()->IsLoadLocal() || | 487 (as_bind->computation()->IsLoadLocal() || |
| 344 as_bind->computation()->IsStoreLocal())) { | 488 as_bind->computation()->IsStoreLocal())) { |
| 345 // Assert exactly one use. | 489 // Remove the load/store from the graph. |
| 346 ASSERT(as_bind->use_list() == v); | |
| 347 ASSERT(as_bind->use_list()->next_use() == NULL); | |
| 348 // Remove the use, its definition and copy the environment value. | |
| 349 v->RemoveFromUseList(); | |
| 350 as_bind->RemoveFromGraph(); | 490 as_bind->RemoveFromGraph(); |
| 351 // Assert we are not referencing nulls in the initial environment. | 491 // Assert we are not referencing nulls in the initial environment. |
| 352 ASSERT(input_defn->ssa_temp_index() != -1); | 492 ASSERT(input_defn->ssa_temp_index() != -1); |
| 353 current->SetInputAt(i, new UseVal(input_defn)); | 493 current->SetInputAt(i, new UseVal(input_defn)); |
| 354 } | 494 } |
| 355 } | 495 } |
| 356 | 496 |
| 357 // Drop pushed arguments for calls. | 497 // Drop pushed arguments for calls. |
| 358 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { | 498 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { |
| 359 env->RemoveLast(); | 499 env->RemoveLast(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 380 index = load->local().BitIndexIn(non_copied_parameter_count_); | 520 index = load->local().BitIndexIn(non_copied_parameter_count_); |
| 381 | 521 |
| 382 PhiInstr* phi = (*env)[index]->AsPhi(); | 522 PhiInstr* phi = (*env)[index]->AsPhi(); |
| 383 if ((phi != NULL) && !phi->is_alive()) { | 523 if ((phi != NULL) && !phi->is_alive()) { |
| 384 phi->mark_alive(); | 524 phi->mark_alive(); |
| 385 live_phis->Add(phi); | 525 live_phis->Add(phi); |
| 386 } | 526 } |
| 387 } | 527 } |
| 388 // Update expression stack or remove from graph. | 528 // Update expression stack or remove from graph. |
| 389 if (bind->is_used()) { | 529 if (bind->is_used()) { |
| 390 // Assert exactly one use. | |
| 391 ASSERT(bind->use_list() != NULL); | |
| 392 ASSERT(bind->use_list()->next_use() == NULL); | |
| 393 env->Add((*env)[index]); | 530 env->Add((*env)[index]); |
| 394 // We remove load/store instructions when we find their use in 2a. | 531 // We remove load/store instructions when we find their use in 2a. |
| 395 } else { | 532 } else { |
| 396 it.RemoveCurrentFromGraph(); | 533 it.RemoveCurrentFromGraph(); |
| 397 } | 534 } |
| 398 } else { | 535 } else { |
| 399 // Not a load or store. | 536 // Not a load or store. |
| 400 if (bind->is_used()) { | 537 if (bind->is_used()) { |
| 401 // Assign fresh SSA temporary and update expression stack. | 538 // Assign fresh SSA temporary and update expression stack. |
| 402 bind->set_ssa_temp_index(alloc_ssa_temp_index()); | 539 bind->set_ssa_temp_index(alloc_ssa_temp_index()); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 601 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 465 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 602 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
| 466 OS::SNPrint(chars, len, kFormat, function_name, reason); | 603 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 467 const Error& error = Error::Handle( | 604 const Error& error = Error::Handle( |
| 468 LanguageError::New(String::Handle(String::New(chars)))); | 605 LanguageError::New(String::Handle(String::New(chars)))); |
| 469 Isolate::Current()->long_jump_base()->Jump(1, error); | 606 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 470 } | 607 } |
| 471 | 608 |
| 472 | 609 |
| 473 } // namespace dart | 610 } // namespace dart |
| OLD | NEW |