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_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/hash_map.h" | 10 #include "vm/hash_map.h" |
| (...skipping 1139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1150 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { | 1150 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { |
| 1151 BlockEntryInstr* candidate = header->PredecessorAt(j); | 1151 BlockEntryInstr* candidate = header->PredecessorAt(j); |
| 1152 if (header->dominator() == candidate) { | 1152 if (header->dominator() == candidate) { |
| 1153 return candidate; | 1153 return candidate; |
| 1154 } | 1154 } |
| 1155 } | 1155 } |
| 1156 return NULL; | 1156 return NULL; |
| 1157 } | 1157 } |
| 1158 | 1158 |
| 1159 | 1159 |
| 1160 void LICM::Hoist(ForwardInstructionIterator* it, | |
|
Florian Schneider
2012/09/07 09:37:00
You could make this a static top-level functions:
Vyacheslav Egorov (Google)
2012/09/07 12:06:00
Unfortunately I can't: it uses friendship relation
| |
| 1161 BlockEntryInstr* pre_header, | |
| 1162 Definition* current) { | |
| 1163 // TODO(fschneider): Avoid repeated deoptimization when | |
| 1164 // speculatively hoisting checks. | |
| 1165 if (FLAG_trace_optimization) { | |
| 1166 OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n", | |
| 1167 current->DebugName(), | |
| 1168 current->deopt_id(), | |
| 1169 current->GetBlock()->block_id(), | |
| 1170 pre_header->block_id()); | |
| 1171 } | |
| 1172 // Move the instruction out of the loop. | |
| 1173 it->RemoveCurrentFromGraph(); | |
| 1174 GotoInstr* last = pre_header->last_instruction()->AsGoto(); | |
| 1175 current->InsertBefore(last); | |
| 1176 // Attach the environment of the Goto instruction to the hoisted | |
| 1177 // instruction and set the correct deopt_id. | |
| 1178 ASSERT(last->env() != NULL); | |
| 1179 last->env()->CopyTo(current); | |
| 1180 current->deopt_id_ = last->GetDeoptId(); | |
|
srdjan
2012/09/07 07:55:26
Could you add tests that have deoptimization cause
Vyacheslav Egorov (Google)
2012/09/07 12:06:00
Done.
| |
| 1181 } | |
| 1182 | |
| 1183 | |
| 1184 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, | |
|
Florian Schneider
2012/09/07 09:37:00
You could make this a static top-level functions:
Vyacheslav Egorov (Google)
2012/09/07 12:06:00
See above.
| |
| 1185 BlockEntryInstr* header, | |
| 1186 BlockEntryInstr* pre_header, | |
| 1187 Definition* current) { | |
| 1188 PhiInstr* phi = current->InputAt(0)->definition()->AsPhi(); | |
| 1189 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { | |
| 1190 return; | |
| 1191 } | |
| 1192 | |
| 1193 if (phi->GetPropagatedCid() == kSmiCid) { | |
|
Florian Schneider
2012/09/07 09:37:00
It should not be necessary to check for redundant
Vyacheslav Egorov (Google)
2012/09/07 12:06:00
There are might be smi checks that are not dominat
| |
| 1194 it->RemoveCurrentFromGraph(); | |
| 1195 return; | |
| 1196 } | |
| 1197 | |
| 1198 // Check if there is only a single kDynamicCid input to the phi that | |
| 1199 // comes from the pre-header. | |
| 1200 const intptr_t kNotFound = -1; | |
| 1201 intptr_t non_smi_input = kNotFound; | |
| 1202 for (intptr_t i = 0; i < phi->InputCount(); ++i) { | |
| 1203 Value* input = phi->InputAt(i); | |
| 1204 if (input->ResultCid() != kSmiCid) { | |
| 1205 if ((non_smi_input != kNotFound) || (input->ResultCid() != kDynamicCid)) { | |
| 1206 // There are multiple kDynamicCid inputs or there is an input that is | |
| 1207 // known to be non-smi. | |
| 1208 return; | |
| 1209 } else { | |
| 1210 non_smi_input = i; | |
| 1211 } | |
| 1212 } | |
| 1213 } | |
| 1214 | |
| 1215 if ((non_smi_input == kNotFound) || | |
| 1216 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { | |
|
Florian Schneider
2012/09/07 09:37:00
It's fine to have the restrict the block where the
| |
| 1217 return; | |
| 1218 } | |
| 1219 | |
| 1220 // Host CheckSmi instruction and make this phi smi one. | |
| 1221 Hoist(it, pre_header, current); | |
| 1222 current->SetInputAt(non_smi_input, phi->InputAt(non_smi_input)); | |
| 1223 phi->SetPropagatedCid(kSmiCid); | |
|
srdjan
2012/09/07 07:55:26
Could/should we run type propagation after LICM ag
Florian Schneider
2012/09/07 09:37:00
Yes, how about building worklist of changed phis
Vyacheslav Egorov (Google)
2012/09/07 12:06:00
Yes, we can. For now I would like to keep it minim
| |
| 1224 } | |
| 1225 | |
| 1226 | |
| 1160 void LICM::Optimize(FlowGraph* flow_graph) { | 1227 void LICM::Optimize(FlowGraph* flow_graph) { |
| 1161 GrowableArray<BlockEntryInstr*> loop_headers; | 1228 GrowableArray<BlockEntryInstr*> loop_headers; |
| 1162 flow_graph->ComputeLoops(&loop_headers); | 1229 flow_graph->ComputeLoops(&loop_headers); |
| 1163 | 1230 |
| 1164 for (intptr_t i = 0; i < loop_headers.length(); ++i) { | 1231 for (intptr_t i = 0; i < loop_headers.length(); ++i) { |
| 1165 BlockEntryInstr* header = loop_headers[i]; | 1232 BlockEntryInstr* header = loop_headers[i]; |
| 1166 // Skip loop that don't have a pre-header block. | 1233 // Skip loop that don't have a pre-header block. |
| 1167 BlockEntryInstr* pre_header = FindPreHeader(header); | 1234 BlockEntryInstr* pre_header = FindPreHeader(header); |
| 1168 if (pre_header == NULL) continue; | 1235 if (pre_header == NULL) continue; |
| 1169 | 1236 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1180 !current->HasSideEffect()) { | 1247 !current->HasSideEffect()) { |
| 1181 bool inputs_loop_invariant = true; | 1248 bool inputs_loop_invariant = true; |
| 1182 for (int i = 0; i < current->InputCount(); ++i) { | 1249 for (int i = 0; i < current->InputCount(); ++i) { |
| 1183 Definition* input_def = current->InputAt(i)->definition(); | 1250 Definition* input_def = current->InputAt(i)->definition(); |
| 1184 if (!input_def->GetBlock()->Dominates(pre_header)) { | 1251 if (!input_def->GetBlock()->Dominates(pre_header)) { |
| 1185 inputs_loop_invariant = false; | 1252 inputs_loop_invariant = false; |
| 1186 break; | 1253 break; |
| 1187 } | 1254 } |
| 1188 } | 1255 } |
| 1189 if (inputs_loop_invariant) { | 1256 if (inputs_loop_invariant) { |
| 1190 // TODO(fschneider): Avoid repeated deoptimization when | 1257 Hoist(&it, pre_header, current); |
| 1191 // speculatively hoisting checks. | 1258 } else if (current->IsCheckSmi() && |
| 1192 if (FLAG_trace_optimization) { | 1259 current->InputAt(0)->definition()->IsPhi()) { |
| 1193 OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n", | 1260 TryHoistCheckSmiThroughPhi(&it, header, pre_header, current); |
| 1194 current->DebugName(), | |
| 1195 current->deopt_id(), | |
| 1196 current->GetBlock()->block_id(), | |
| 1197 pre_header->block_id()); | |
| 1198 } | |
| 1199 // Move the instruction out of the loop. | |
| 1200 it.RemoveCurrentFromGraph(); | |
| 1201 GotoInstr* last = pre_header->last_instruction()->AsGoto(); | |
| 1202 current->InsertBefore(last); | |
| 1203 // Attach the environment of the Goto instruction to the hoisted | |
| 1204 // instruction and set the correct deopt_id. | |
| 1205 ASSERT(last->env() != NULL); | |
| 1206 last->env()->CopyTo(current); | |
| 1207 current->deopt_id_ = last->GetDeoptId(); | |
| 1208 } | 1261 } |
| 1209 } | 1262 } |
| 1210 } | 1263 } |
| 1211 } | 1264 } |
| 1212 } | 1265 } |
| 1213 } | 1266 } |
| 1214 | 1267 |
| 1215 | 1268 |
| 1216 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { | 1269 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { |
| 1217 ASSERT(graph_entry->IsGraphEntry()); | 1270 ASSERT(graph_entry->IsGraphEntry()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1249 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. | 1302 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. |
| 1250 OptimizeRecursive(child, &child_map); | 1303 OptimizeRecursive(child, &child_map); |
| 1251 } else { | 1304 } else { |
| 1252 OptimizeRecursive(child, map); // Reuse map for the last child. | 1305 OptimizeRecursive(child, map); // Reuse map for the last child. |
| 1253 } | 1306 } |
| 1254 } | 1307 } |
| 1255 } | 1308 } |
| 1256 | 1309 |
| 1257 | 1310 |
| 1258 } // namespace dart | 1311 } // namespace dart |
| OLD | NEW |