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 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 | 254 |
| 255 // Used by TryMergeDivMod. | 255 // Used by TryMergeDivMod. |
| 256 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction, | 256 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction, |
| 257 // and the using instruction. This is an intermediate step before merging. | 257 // and the using instruction. This is an intermediate step before merging. |
| 258 static void DivModAppendLoadIndexed(BinarySmiOpInstr* instr, | 258 void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr, |
| 259 FlowGraph* flow_graph) { | 259 intptr_t ix, |
| 260 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid); | 260 intptr_t cid) { |
| 261 const intptr_t ix = (instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1; | 261 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(cid); |
| 262 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix))); | 262 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix))); |
| 263 flow_graph->InsertAfter(instr, index_instr, NULL, Definition::kValue); | 263 flow_graph()->InsertAfter(instr, index_instr, NULL, Definition::kValue); |
| 264 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr), | 264 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr), |
| 265 new Value(index_instr), | 265 new Value(index_instr), |
| 266 index_scale, | 266 index_scale, |
| 267 kArrayCid, | 267 cid, |
| 268 Isolate::kNoDeoptId); | 268 Isolate::kNoDeoptId); |
| 269 instr->ReplaceUsesWith(load); | 269 instr->ReplaceUsesWith(load); |
| 270 flow_graph->InsertAfter(index_instr, load, NULL, Definition::kValue); | 270 flow_graph()->InsertAfter(index_instr, load, NULL, Definition::kValue); |
| 271 } | 271 } |
| 272 | 272 |
| 273 | 273 |
| 274 // Dart: | 274 // Dart: |
| 275 // var x = d % 10; | 275 // var x = d % 10; |
| 276 // var y = d ~/ 10; | 276 // var y = d ~/ 10; |
| 277 // var z = x + y; | 277 // var z = x + y; |
| 278 // | 278 // |
| 279 // IL: | 279 // IL: |
| 280 // v4 <- %(v2, v3) | 280 // v4 <- %(v2, v3) |
| 281 // v5 <- ~/(v2, v3) | 281 // v5 <- ~/(v2, v3) |
| 282 // v6 <- +(v4, v5) | 282 // v6 <- +(v4, v5) |
| 283 // | 283 // |
| 284 // IL optimized: | 284 // IL optimized: |
| 285 // v4 <- DIVMOD(v2, v3); | 285 // v4 <- DIVMOD(v2, v3); |
| 286 // v5 <- LoadIndexed(v4, 0); // ~/ result | 286 // v5 <- LoadIndexed(v4, 0); // ~/ result |
| 287 // v6 <- LoadIndexed(v4, 1); // % result | 287 // v6 <- LoadIndexed(v4, 1); // % result |
| 288 // v7 <- +(v5, v6) | 288 // v7 <- +(v5, v6) |
| 289 // Because of the environment it is important that merged instruction replaces | 289 // Because of the environment it is important that merged instruction replaces |
| 290 // first original instruction encountered. | 290 // first original instruction encountered. |
| 291 void FlowGraphOptimizer::TryMergeTruncDivMod( | 291 void FlowGraphOptimizer::TryMergeTruncDivMod( |
| 292 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { | 292 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { |
| 293 if (merge_candidates->length() < 2) { | 293 if (merge_candidates->length() < 2) { |
| 294 // Need at least a TRUNCDIV and a MOD. | 294 // Need at least a TRUNCDIV and a MOD. |
| 295 return; | 295 return; |
| 296 } | 296 } |
| 297 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 297 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| 298 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; | 298 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; |
| 299 if (curr_instr == NULL) { | 299 if (curr_instr == NULL) { |
| 300 // Instructions was merged already. | 300 // Instruction was merged already. |
| 301 continue; | 301 continue; |
| 302 } | 302 } |
| 303 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) || | 303 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) || |
| 304 (curr_instr->op_kind() == Token::kMOD)); | 304 (curr_instr->op_kind() == Token::kMOD)); |
| 305 // Check if there is kMOD/kTRUNDIV binop with same inputs. | 305 // Check if there is kMOD/kTRUNDIV binop with same inputs. |
| 306 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ? | 306 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ? |
| 307 Token::kMOD : Token::kTRUNCDIV; | 307 Token::kMOD : Token::kTRUNCDIV; |
| 308 Definition* left_def = curr_instr->left()->definition(); | 308 Definition* left_def = curr_instr->left()->definition(); |
| 309 Definition* right_def = curr_instr->right()->definition(); | 309 Definition* right_def = curr_instr->right()->definition(); |
| 310 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { | 310 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { |
| 311 BinarySmiOpInstr* other_binop = (*merge_candidates)[k]; | 311 BinarySmiOpInstr* other_binop = (*merge_candidates)[k]; |
| 312 // 'other_binop' can be NULL if it was already merged. | 312 // 'other_binop' can be NULL if it was already merged. |
| 313 if ((other_binop != NULL) && | 313 if ((other_binop != NULL) && |
| 314 (other_binop->op_kind() == other_kind) && | 314 (other_binop->op_kind() == other_kind) && |
| 315 (other_binop->left()->definition() == left_def) && | 315 (other_binop->left()->definition() == left_def) && |
| 316 (other_binop->right()->definition() == right_def)) { | 316 (other_binop->right()->definition() == right_def)) { |
| 317 (*merge_candidates)[k] = NULL; // Clear it. | 317 (*merge_candidates)[k] = NULL; // Clear it. |
| 318 // Append a LoadIndexed behind TRUNC_DIV and MOD. | 318 // Append a LoadIndexed behind TRUNC_DIV and MOD. |
| 319 DivModAppendLoadIndexed(curr_instr, flow_graph_); | 319 const intptr_t curr_result_ix = |
| 320 DivModAppendLoadIndexed(other_binop, flow_graph_); | 320 (curr_instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1; |
| 321 AppendLoadIndexedForMerged(curr_instr, curr_result_ix, kArrayCid); | |
| 322 const intptr_t other_result_ix = | |
|
Florian Schneider
2013/12/03 14:12:04
Equivalent, but shorter:
const intptr_t other_res
| |
| 323 (other_binop->op_kind() == Token::kTRUNCDIV) ? 0 : 1; | |
| 324 AppendLoadIndexedForMerged(other_binop, other_result_ix, kArrayCid); | |
| 321 | 325 |
| 322 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); | 326 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); |
| 323 args->Add(new Value(curr_instr->left()->definition())); | 327 args->Add(new Value(curr_instr->left()->definition())); |
| 324 args->Add(new Value(curr_instr->right()->definition())); | 328 args->Add(new Value(curr_instr->right()->definition())); |
| 325 | 329 |
| 326 // Replace with TruncDivMod. | 330 // Replace with TruncDivMod. |
| 327 MergedMathInstr* div_mod = new MergedMathInstr( | 331 MergedMathInstr* div_mod = new MergedMathInstr( |
| 328 args, | 332 args, |
| 329 curr_instr->deopt_id(), | 333 curr_instr->deopt_id(), |
| 330 MergedMathInstr::kTruncDivMod); | 334 MergedMathInstr::kTruncDivMod); |
| 331 curr_instr->ReplaceWith(div_mod, current_iterator()); | 335 curr_instr->ReplaceWith(div_mod, current_iterator()); |
| 332 other_binop->ReplaceUsesWith(div_mod); | 336 other_binop->ReplaceUsesWith(div_mod); |
| 333 other_binop->RemoveFromGraph(); | 337 other_binop->RemoveFromGraph(); |
| 334 } | 338 } |
| 335 } | 339 } |
| 336 } | 340 } |
| 337 } | 341 } |
| 338 | 342 |
| 339 | 343 |
| 344 void FlowGraphOptimizer::TryMergeMathUnary( | |
| 345 GrowableArray<MathUnaryInstr*>* merge_candidates) { | |
| 346 if (!FlowGraphCompiler::SupportsSinCos()) { | |
| 347 return; | |
| 348 } | |
| 349 if (merge_candidates->length() < 2) { | |
| 350 // Need at least a SIN and a COS. | |
| 351 return; | |
| 352 } | |
| 353 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | |
| 354 MathUnaryInstr* curr_instr = (*merge_candidates)[i]; | |
| 355 if (curr_instr == NULL) { | |
| 356 // Instruction was merged already. | |
| 357 continue; | |
| 358 } | |
| 359 ASSERT((curr_instr->kind() == MethodRecognizer::kMathSin) || | |
| 360 (curr_instr->kind() == MethodRecognizer::kMathCos)); | |
| 361 // Check if there is sin/cos binop with same inputs. | |
| 362 const intptr_t other_kind = | |
| 363 (curr_instr->kind() == MethodRecognizer::kMathSin) ? | |
| 364 MethodRecognizer::kMathCos : MethodRecognizer::kMathSin; | |
| 365 Definition* def = curr_instr->value()->definition(); | |
| 366 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { | |
| 367 MathUnaryInstr* other_op = (*merge_candidates)[k]; | |
| 368 // 'other_op' can be NULL if it was already merged. | |
| 369 if ((other_op != NULL) && (other_op->kind() == other_kind) && | |
| 370 (other_op->value()->definition() == def)) { | |
| 371 (*merge_candidates)[k] = NULL; // Clear it. | |
| 372 // Append a LoadIndexed behind SIN and COS. | |
| 373 const intptr_t curr_result_ix = | |
| 374 (curr_instr->kind() == MethodRecognizer::kMathSin) ? 0 : 1; | |
| 375 AppendLoadIndexedForMerged( | |
| 376 curr_instr, curr_result_ix, kTypedDataFloat64ArrayCid); | |
| 377 const intptr_t other_result_ix = | |
| 378 (other_op->kind() == MethodRecognizer::kMathSin) ? 0 : 1; | |
|
Florian Schneider
2013/12/03 14:12:04
Equivalent, but shorter:
const intptr_t other_res
srdjan
2013/12/03 18:10:01
I used to have that, but found it harder to read.
| |
| 379 AppendLoadIndexedForMerged( | |
| 380 other_op, other_result_ix, kTypedDataFloat64ArrayCid); | |
| 381 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); | |
|
Florian Schneider
2013/12/03 14:12:04
s/2/1/
because only one argument is added below.
srdjan
2013/12/03 18:10:01
Done.
| |
| 382 args->Add(new Value(curr_instr->value()->definition())); | |
| 383 | |
| 384 // Replace with TruncDivMod. | |
| 385 MergedMathInstr* div_mod = new MergedMathInstr( | |
| 386 args, | |
| 387 curr_instr->DeoptimizationTarget(), | |
| 388 MergedMathInstr::kSinCos); | |
| 389 curr_instr->ReplaceWith(div_mod, current_iterator()); | |
| 390 other_op->ReplaceUsesWith(div_mod); | |
| 391 other_op->RemoveFromGraph(); | |
| 392 } | |
| 393 } | |
| 394 } | |
| 395 } | |
| 396 | |
| 397 | |
| 340 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 398 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
| 341 // shift can be a truncating Smi shift-left and result is always Smi. | 399 // shift can be a truncating Smi shift-left and result is always Smi. |
| 342 // Merging occurs only per basic-block. | 400 // Merging occurs only per basic-block. |
| 343 void FlowGraphOptimizer::TryOptimizePatterns() { | 401 void FlowGraphOptimizer::TryOptimizePatterns() { |
| 344 if (!FLAG_truncating_left_shift) return; | 402 if (!FLAG_truncating_left_shift) return; |
| 345 ASSERT(current_iterator_ == NULL); | 403 ASSERT(current_iterator_ == NULL); |
| 346 GrowableArray<BinarySmiOpInstr*> for_merge; | 404 GrowableArray<BinarySmiOpInstr*> div_mod_merge; |
| 405 GrowableArray<MathUnaryInstr*> sin_cos_merge; | |
| 347 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 406 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 348 // Merging only per basic-block. | 407 // Merging only per basic-block. |
| 349 for_merge.Clear(); | 408 div_mod_merge.Clear(); |
| 409 sin_cos_merge.Clear(); | |
| 350 BlockEntryInstr* entry = block_order_[i]; | 410 BlockEntryInstr* entry = block_order_[i]; |
| 351 ForwardInstructionIterator it(entry); | 411 ForwardInstructionIterator it(entry); |
| 352 current_iterator_ = ⁢ | 412 current_iterator_ = ⁢ |
| 353 for (; !it.Done(); it.Advance()) { | 413 for (; !it.Done(); it.Advance()) { |
| 354 if (it.Current()->IsBinarySmiOp()) { | 414 if (it.Current()->IsBinarySmiOp()) { |
| 355 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); | 415 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); |
| 356 if (binop->op_kind() == Token::kBIT_AND) { | 416 if (binop->op_kind() == Token::kBIT_AND) { |
| 357 OptimizeLeftShiftBitAndSmiOp(binop, | 417 OptimizeLeftShiftBitAndSmiOp(binop, |
| 358 binop->left()->definition(), | 418 binop->left()->definition(), |
| 359 binop->right()->definition()); | 419 binop->right()->definition()); |
| 360 } else if ((binop->op_kind() == Token::kTRUNCDIV) || | 420 } else if ((binop->op_kind() == Token::kTRUNCDIV) || |
| 361 (binop->op_kind() == Token::kMOD)) { | 421 (binop->op_kind() == Token::kMOD)) { |
| 362 for_merge.Add(binop); | 422 div_mod_merge.Add(binop); |
| 363 } | 423 } |
| 364 } else if (it.Current()->IsBinaryMintOp()) { | 424 } else if (it.Current()->IsBinaryMintOp()) { |
| 365 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); | 425 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); |
| 366 if (mintop->op_kind() == Token::kBIT_AND) { | 426 if (mintop->op_kind() == Token::kBIT_AND) { |
| 367 OptimizeLeftShiftBitAndSmiOp(mintop, | 427 OptimizeLeftShiftBitAndSmiOp(mintop, |
| 368 mintop->left()->definition(), | 428 mintop->left()->definition(), |
| 369 mintop->right()->definition()); | 429 mintop->right()->definition()); |
| 370 } | 430 } |
| 431 } else if (it.Current()->IsMathUnary()) { | |
| 432 MathUnaryInstr* math_unary = it.Current()->AsMathUnary(); | |
| 433 if ((math_unary->kind() == MethodRecognizer::kMathSin) || | |
| 434 (math_unary->kind() == MethodRecognizer::kMathCos)) { | |
| 435 sin_cos_merge.Add(math_unary); | |
| 436 } | |
| 371 } | 437 } |
| 372 } | 438 } |
| 373 TryMergeTruncDivMod(&for_merge); | 439 TryMergeTruncDivMod(&div_mod_merge); |
| 440 TryMergeMathUnary(&sin_cos_merge); | |
| 374 current_iterator_ = NULL; | 441 current_iterator_ = NULL; |
| 375 } | 442 } |
| 376 } | 443 } |
| 377 | 444 |
| 378 | 445 |
| 379 static void EnsureSSATempIndex(FlowGraph* graph, | 446 static void EnsureSSATempIndex(FlowGraph* graph, |
| 380 Definition* defn, | 447 Definition* defn, |
| 381 Definition* replacement) { | 448 Definition* replacement) { |
| 382 if ((replacement->ssa_temp_index() == -1) && | 449 if ((replacement->ssa_temp_index() == -1) && |
| 383 (defn->ssa_temp_index() != -1)) { | 450 (defn->ssa_temp_index() != -1)) { |
| (...skipping 7592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7976 } | 8043 } |
| 7977 | 8044 |
| 7978 // Insert materializations at environment uses. | 8045 // Insert materializations at environment uses. |
| 7979 for (intptr_t i = 0; i < exits.length(); i++) { | 8046 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7980 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8047 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7981 } | 8048 } |
| 7982 } | 8049 } |
| 7983 | 8050 |
| 7984 | 8051 |
| 7985 } // namespace dart | 8052 } // namespace dart |
| OLD | NEW |