| 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 AppendLoadIndexedForMerged( |
| 320 DivModAppendLoadIndexed(other_binop, flow_graph_); | 320 curr_instr, |
| 321 MergedMathInstr::ResultIndexOf(curr_instr->op_kind()), |
| 322 kArrayCid); |
| 323 AppendLoadIndexedForMerged( |
| 324 other_binop, |
| 325 MergedMathInstr::ResultIndexOf(other_binop->op_kind()), |
| 326 kArrayCid); |
| 321 | 327 |
| 322 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); | 328 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2); |
| 323 args->Add(new Value(curr_instr->left()->definition())); | 329 args->Add(new Value(curr_instr->left()->definition())); |
| 324 args->Add(new Value(curr_instr->right()->definition())); | 330 args->Add(new Value(curr_instr->right()->definition())); |
| 325 | 331 |
| 326 // Replace with TruncDivMod. | 332 // Replace with TruncDivMod. |
| 327 MergedMathInstr* div_mod = new MergedMathInstr( | 333 MergedMathInstr* div_mod = new MergedMathInstr( |
| 328 args, | 334 args, |
| 329 curr_instr->deopt_id(), | 335 curr_instr->deopt_id(), |
| 330 MergedMathInstr::kTruncDivMod); | 336 MergedMathInstr::kTruncDivMod); |
| 331 curr_instr->ReplaceWith(div_mod, current_iterator()); | 337 curr_instr->ReplaceWith(div_mod, current_iterator()); |
| 332 other_binop->ReplaceUsesWith(div_mod); | 338 other_binop->ReplaceUsesWith(div_mod); |
| 333 other_binop->RemoveFromGraph(); | 339 other_binop->RemoveFromGraph(); |
| 334 } | 340 } |
| 335 } | 341 } |
| 336 } | 342 } |
| 337 } | 343 } |
| 338 | 344 |
| 339 | 345 |
| 346 void FlowGraphOptimizer::TryMergeMathUnary( |
| 347 GrowableArray<MathUnaryInstr*>* merge_candidates) { |
| 348 if (!FlowGraphCompiler::SupportsSinCos()) { |
| 349 return; |
| 350 } |
| 351 if (merge_candidates->length() < 2) { |
| 352 // Need at least a SIN and a COS. |
| 353 return; |
| 354 } |
| 355 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| 356 MathUnaryInstr* curr_instr = (*merge_candidates)[i]; |
| 357 if (curr_instr == NULL) { |
| 358 // Instruction was merged already. |
| 359 continue; |
| 360 } |
| 361 ASSERT((curr_instr->kind() == MethodRecognizer::kMathSin) || |
| 362 (curr_instr->kind() == MethodRecognizer::kMathCos)); |
| 363 // Check if there is sin/cos binop with same inputs. |
| 364 const intptr_t other_kind = |
| 365 (curr_instr->kind() == MethodRecognizer::kMathSin) ? |
| 366 MethodRecognizer::kMathCos : MethodRecognizer::kMathSin; |
| 367 Definition* def = curr_instr->value()->definition(); |
| 368 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) { |
| 369 MathUnaryInstr* other_op = (*merge_candidates)[k]; |
| 370 // 'other_op' can be NULL if it was already merged. |
| 371 if ((other_op != NULL) && (other_op->kind() == other_kind) && |
| 372 (other_op->value()->definition() == def)) { |
| 373 (*merge_candidates)[k] = NULL; // Clear it. |
| 374 // Append a LoadIndexed behind SIN and COS. |
| 375 AppendLoadIndexedForMerged( |
| 376 curr_instr, |
| 377 MergedMathInstr::ResultIndexOf(curr_instr->kind()), |
| 378 kTypedDataFloat64ArrayCid); |
| 379 AppendLoadIndexedForMerged( |
| 380 other_op, |
| 381 MergedMathInstr::ResultIndexOf(other_op->kind()), |
| 382 kTypedDataFloat64ArrayCid); |
| 383 ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(1); |
| 384 args->Add(new Value(curr_instr->value()->definition())); |
| 385 |
| 386 // Replace with TruncDivMod. |
| 387 MergedMathInstr* div_mod = new MergedMathInstr( |
| 388 args, |
| 389 curr_instr->DeoptimizationTarget(), |
| 390 MergedMathInstr::kSinCos); |
| 391 curr_instr->ReplaceWith(div_mod, current_iterator()); |
| 392 other_op->ReplaceUsesWith(div_mod); |
| 393 other_op->RemoveFromGraph(); |
| 394 OS::Print("Merged SINCOS\n"); |
| 395 } |
| 396 } |
| 397 } |
| 398 } |
| 399 |
| 400 |
| 340 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 401 // 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. | 402 // shift can be a truncating Smi shift-left and result is always Smi. |
| 342 // Merging occurs only per basic-block. | 403 // Merging occurs only per basic-block. |
| 343 void FlowGraphOptimizer::TryOptimizePatterns() { | 404 void FlowGraphOptimizer::TryOptimizePatterns() { |
| 344 if (!FLAG_truncating_left_shift) return; | 405 if (!FLAG_truncating_left_shift) return; |
| 345 ASSERT(current_iterator_ == NULL); | 406 ASSERT(current_iterator_ == NULL); |
| 346 GrowableArray<BinarySmiOpInstr*> for_merge; | 407 GrowableArray<BinarySmiOpInstr*> div_mod_merge; |
| 408 GrowableArray<MathUnaryInstr*> sin_cos_merge; |
| 347 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 409 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 348 // Merging only per basic-block. | 410 // Merging only per basic-block. |
| 349 for_merge.Clear(); | 411 div_mod_merge.Clear(); |
| 412 sin_cos_merge.Clear(); |
| 350 BlockEntryInstr* entry = block_order_[i]; | 413 BlockEntryInstr* entry = block_order_[i]; |
| 351 ForwardInstructionIterator it(entry); | 414 ForwardInstructionIterator it(entry); |
| 352 current_iterator_ = ⁢ | 415 current_iterator_ = ⁢ |
| 353 for (; !it.Done(); it.Advance()) { | 416 for (; !it.Done(); it.Advance()) { |
| 354 if (it.Current()->IsBinarySmiOp()) { | 417 if (it.Current()->IsBinarySmiOp()) { |
| 355 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); | 418 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); |
| 356 if (binop->op_kind() == Token::kBIT_AND) { | 419 if (binop->op_kind() == Token::kBIT_AND) { |
| 357 OptimizeLeftShiftBitAndSmiOp(binop, | 420 OptimizeLeftShiftBitAndSmiOp(binop, |
| 358 binop->left()->definition(), | 421 binop->left()->definition(), |
| 359 binop->right()->definition()); | 422 binop->right()->definition()); |
| 360 } else if ((binop->op_kind() == Token::kTRUNCDIV) || | 423 } else if ((binop->op_kind() == Token::kTRUNCDIV) || |
| 361 (binop->op_kind() == Token::kMOD)) { | 424 (binop->op_kind() == Token::kMOD)) { |
| 362 for_merge.Add(binop); | 425 div_mod_merge.Add(binop); |
| 363 } | 426 } |
| 364 } else if (it.Current()->IsBinaryMintOp()) { | 427 } else if (it.Current()->IsBinaryMintOp()) { |
| 365 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); | 428 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); |
| 366 if (mintop->op_kind() == Token::kBIT_AND) { | 429 if (mintop->op_kind() == Token::kBIT_AND) { |
| 367 OptimizeLeftShiftBitAndSmiOp(mintop, | 430 OptimizeLeftShiftBitAndSmiOp(mintop, |
| 368 mintop->left()->definition(), | 431 mintop->left()->definition(), |
| 369 mintop->right()->definition()); | 432 mintop->right()->definition()); |
| 370 } | 433 } |
| 434 } else if (it.Current()->IsMathUnary()) { |
| 435 MathUnaryInstr* math_unary = it.Current()->AsMathUnary(); |
| 436 if ((math_unary->kind() == MethodRecognizer::kMathSin) || |
| 437 (math_unary->kind() == MethodRecognizer::kMathCos)) { |
| 438 sin_cos_merge.Add(math_unary); |
| 439 } |
| 371 } | 440 } |
| 372 } | 441 } |
| 373 TryMergeTruncDivMod(&for_merge); | 442 TryMergeTruncDivMod(&div_mod_merge); |
| 443 TryMergeMathUnary(&sin_cos_merge); |
| 374 current_iterator_ = NULL; | 444 current_iterator_ = NULL; |
| 375 } | 445 } |
| 376 } | 446 } |
| 377 | 447 |
| 378 | 448 |
| 379 static void EnsureSSATempIndex(FlowGraph* graph, | 449 static void EnsureSSATempIndex(FlowGraph* graph, |
| 380 Definition* defn, | 450 Definition* defn, |
| 381 Definition* replacement) { | 451 Definition* replacement) { |
| 382 if ((replacement->ssa_temp_index() == -1) && | 452 if ((replacement->ssa_temp_index() == -1) && |
| 383 (defn->ssa_temp_index() != -1)) { | 453 (defn->ssa_temp_index() != -1)) { |
| (...skipping 7592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7976 } | 8046 } |
| 7977 | 8047 |
| 7978 // Insert materializations at environment uses. | 8048 // Insert materializations at environment uses. |
| 7979 for (intptr_t i = 0; i < exits.length(); i++) { | 8049 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7980 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8050 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7981 } | 8051 } |
| 7982 } | 8052 } |
| 7983 | 8053 |
| 7984 | 8054 |
| 7985 } // namespace dart | 8055 } // namespace dart |
| OLD | NEW |