Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 BinarySmiOpInstr* smi_op = new BinarySmiOpInstr( | 244 BinarySmiOpInstr* smi_op = new BinarySmiOpInstr( |
| 245 Token::kBIT_AND, | 245 Token::kBIT_AND, |
| 246 new Value(left_instr), | 246 new Value(left_instr), |
| 247 new Value(right_instr), | 247 new Value(right_instr), |
| 248 Isolate::kNoDeoptId); // BIT_AND cannot deoptimize. | 248 Isolate::kNoDeoptId); // BIT_AND cannot deoptimize. |
| 249 bit_and_instr->ReplaceWith(smi_op, current_iterator()); | 249 bit_and_instr->ReplaceWith(smi_op, current_iterator()); |
| 250 } | 250 } |
| 251 } | 251 } |
| 252 | 252 |
| 253 | 253 |
| 254 | |
| 255 // Used by TryMergeDivMod. | |
| 256 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction, | |
| 257 // and the using instruction. This is an intermediate step before merging. | |
| 258 static void DivModAppendLoadIndexed(BinarySmiOpInstr* instr, | |
| 259 FlowGraph* flow_graph) { | |
| 260 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); | |
| 261 const intptr_t ix = (instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1; | |
| 262 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix))); | |
| 263 flow_graph->InsertAfter(instr, index_instr, NULL, Definition::kValue); | |
| 264 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr), | |
| 265 new Value(index_instr), | |
| 266 index_scale, | |
| 267 kArrayCid, | |
| 268 Isolate::kNoDeoptId); | |
| 269 instr->ReplaceUsesWith(load); | |
| 270 flow_graph->InsertAfter(index_instr, load, NULL, Definition::kValue); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 // Dart: | |
| 275 // var x = d % 10; | |
| 276 // var y = d ~/ 10; | |
| 277 // var z = x + y; | |
| 278 // | |
| 279 // IL: | |
| 280 // v4 <- %(v2, v3) | |
| 281 // v5 <- ~/(v2, v3) | |
| 282 // v6 <- +(v4, v5) | |
| 283 // | |
| 284 // IL optimized: | |
| 285 // v4 <- DIVMOD(v2, v3); | |
| 286 // v5 <- LoadIndexed(v4, 0); // ~/ result | |
| 287 // v6 <- LoadIndexed(v4, 1); // % result | |
| 288 // v7 <- +(v5, v6) | |
| 289 // Because of the environment it is important that merged instruction replaces | |
| 290 // first original instruction encountered. | |
| 291 void FlowGraphOptimizer::TryMergeTruncDivMod( | |
| 292 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { | |
| 293 if (merge_candidates->length() < 2) { | |
| 294 // Need at least a TRUNCDIV and a MOD. | |
| 295 return; | |
| 296 } | |
| 297 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | |
| 298 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; | |
| 299 if (curr_instr == NULL) { | |
| 300 // Instructions was merged already. | |
| 301 continue; | |
| 302 } | |
| 303 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) || | |
| 304 (curr_instr->op_kind() == Token::kMOD)); | |
| 305 // Check if there is kMOD/kTRUNDIV binop with same inputs. | |
| 306 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ? | |
| 307 Token::kMOD : Token::kTRUNCDIV; | |
| 308 Definition* left_def = curr_instr->left()->definition(); | |
| 309 Definition* right_def = curr_instr->right()->definition(); | |
| 310 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { | |
| 311 BinarySmiOpInstr* other_binop = (*merge_candidates)[k]; | |
|
Florian Schneider
2013/11/21 11:15:41
Can ohter_binop ever be NULL? I'm thinking of the
srdjan
2013/11/21 17:32:44
Indeed it can.. fixed. Added tests as suggested
| |
| 312 if ((other_binop->op_kind() == other_kind) && | |
| 313 (other_binop->left()->definition() == left_def) && | |
| 314 (other_binop->right()->definition() == right_def)) { | |
| 315 (*merge_candidates)[k] = NULL; // Clear it. | |
| 316 // Append a LoadIndexed behind TRUNC_DIV and MOD. | |
| 317 DivModAppendLoadIndexed(curr_instr, flow_graph_); | |
| 318 DivModAppendLoadIndexed(other_binop, flow_graph_); | |
| 319 | |
| 320 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); | |
| 321 args->Add(new Value(curr_instr->left()->definition())); | |
| 322 args->Add(new Value(curr_instr->right()->definition())); | |
| 323 | |
| 324 // Replace with TruncDivMod. | |
| 325 MergedMathInstr* div_mod = new MergedMathInstr( | |
| 326 args, | |
| 327 curr_instr->deopt_id(), | |
| 328 MergedMathInstr::kTruncDivMod); | |
| 329 curr_instr->ReplaceWith(div_mod, current_iterator()); | |
| 330 other_binop->ReplaceUsesWith(div_mod); | |
| 331 other_binop->RemoveFromGraph(); | |
| 332 } | |
| 333 } | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 | |
| 254 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 338 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
| 255 // shift can be a truncating Smi shift-left and result is always Smi. | 339 // shift can be a truncating Smi shift-left and result is always Smi. |
| 256 void FlowGraphOptimizer::TryOptimizeLeftShiftWithBitAndPattern() { | 340 void FlowGraphOptimizer::TryOptimizePatterns() { |
| 257 if (!FLAG_truncating_left_shift) return; | 341 if (!FLAG_truncating_left_shift) return; |
| 258 ASSERT(current_iterator_ == NULL); | 342 ASSERT(current_iterator_ == NULL); |
| 343 GrowableArray<BinarySmiOpInstr*> for_merge; | |
| 259 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 344 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 345 for_merge.Clear(); | |
|
Florian Schneider
2013/11/21 11:15:41
Maybe add a comment here or in TryMergeTruncDivMod
srdjan
2013/11/21 17:32:44
Done.
| |
| 260 BlockEntryInstr* entry = block_order_[i]; | 346 BlockEntryInstr* entry = block_order_[i]; |
| 261 ForwardInstructionIterator it(entry); | 347 ForwardInstructionIterator it(entry); |
| 262 current_iterator_ = ⁢ | 348 current_iterator_ = ⁢ |
| 263 for (; !it.Done(); it.Advance()) { | 349 for (; !it.Done(); it.Advance()) { |
| 264 if (it.Current()->IsBinarySmiOp()) { | 350 if (it.Current()->IsBinarySmiOp()) { |
| 265 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); | 351 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); |
| 266 if (binop->op_kind() == Token::kBIT_AND) { | 352 if (binop->op_kind() == Token::kBIT_AND) { |
| 267 OptimizeLeftShiftBitAndSmiOp(binop, | 353 OptimizeLeftShiftBitAndSmiOp(binop, |
| 268 binop->left()->definition(), | 354 binop->left()->definition(), |
| 269 binop->right()->definition()); | 355 binop->right()->definition()); |
| 356 } else if ((binop->op_kind() == Token::kTRUNCDIV) || | |
| 357 (binop->op_kind() == Token::kMOD)) { | |
| 358 for_merge.Add(binop); | |
| 270 } | 359 } |
| 271 } else if (it.Current()->IsBinaryMintOp()) { | 360 } else if (it.Current()->IsBinaryMintOp()) { |
| 272 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); | 361 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); |
| 273 if (mintop->op_kind() == Token::kBIT_AND) { | 362 if (mintop->op_kind() == Token::kBIT_AND) { |
| 274 OptimizeLeftShiftBitAndSmiOp(mintop, | 363 OptimizeLeftShiftBitAndSmiOp(mintop, |
| 275 mintop->left()->definition(), | 364 mintop->left()->definition(), |
| 276 mintop->right()->definition()); | 365 mintop->right()->definition()); |
| 277 } | 366 } |
| 278 } | 367 } |
| 279 } | 368 } |
| 369 TryMergeTruncDivMod(&for_merge); | |
| 280 current_iterator_ = NULL; | 370 current_iterator_ = NULL; |
| 281 } | 371 } |
| 282 } | 372 } |
| 283 | 373 |
| 284 | 374 |
| 285 static void EnsureSSATempIndex(FlowGraph* graph, | 375 static void EnsureSSATempIndex(FlowGraph* graph, |
| 286 Definition* defn, | 376 Definition* defn, |
| 287 Definition* replacement) { | 377 Definition* replacement) { |
| 288 if ((replacement->ssa_temp_index() == -1) && | 378 if ((replacement->ssa_temp_index() == -1) && |
| 289 (defn->ssa_temp_index() != -1)) { | 379 (defn->ssa_temp_index() != -1)) { |
| (...skipping 6533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6823 SetValue(instr, non_constant_); | 6913 SetValue(instr, non_constant_); |
| 6824 } | 6914 } |
| 6825 | 6915 |
| 6826 | 6916 |
| 6827 void ConstantPropagator::VisitInvokeMathCFunction( | 6917 void ConstantPropagator::VisitInvokeMathCFunction( |
| 6828 InvokeMathCFunctionInstr* instr) { | 6918 InvokeMathCFunctionInstr* instr) { |
| 6829 // TODO(kmillikin): Handle conversion. | 6919 // TODO(kmillikin): Handle conversion. |
| 6830 SetValue(instr, non_constant_); | 6920 SetValue(instr, non_constant_); |
| 6831 } | 6921 } |
| 6832 | 6922 |
| 6923 | |
| 6924 void ConstantPropagator::VisitMergedMath(MergedMathInstr* instr) { | |
| 6925 // TODO(kmillikin): Handle conversion. | |
|
srdjan
2013/11/20 22:23:28
Just standard boiler-plate :-).
Florian Schneider
2013/11/21 11:15:41
The comment still does not make sense since this i
srdjan
2013/11/21 17:32:44
// TODO(srdjan): Handle merged instruction.
| |
| 6926 SetValue(instr, non_constant_); | |
| 6927 } | |
| 6928 | |
| 6929 | |
| 6833 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { | 6930 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { |
| 6834 SetValue(instr, instr->value()); | 6931 SetValue(instr, instr->value()); |
| 6835 } | 6932 } |
| 6836 | 6933 |
| 6837 | 6934 |
| 6838 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { | 6935 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { |
| 6839 // Should not be used outside of range analysis. | 6936 // Should not be used outside of range analysis. |
| 6840 UNREACHABLE(); | 6937 UNREACHABLE(); |
| 6841 } | 6938 } |
| 6842 | 6939 |
| (...skipping 1069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7912 } | 8009 } |
| 7913 | 8010 |
| 7914 // Insert materializations at environment uses. | 8011 // Insert materializations at environment uses. |
| 7915 for (intptr_t i = 0; i < exits.length(); i++) { | 8012 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7916 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8013 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7917 } | 8014 } |
| 7918 } | 8015 } |
| 7919 | 8016 |
| 7920 | 8017 |
| 7921 } // namespace dart | 8018 } // namespace dart |
| OLD | NEW |