Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: runtime/vm/aot_optimizer.cc

Issue 2265873005: VM: Remove more duplicate code between AOT and JIT compiler. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/aot_optimizer.h" 5 #include "vm/aot_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 ic_data.NumArgsTested(), false)); 259 ic_data.NumArgsTested(), false));
260 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); 260 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
261 new_ic_data.AddReceiverCheck(cid, function); 261 new_ic_data.AddReceiverCheck(cid, function);
262 return new_ic_data; 262 return new_ic_data;
263 } 263 }
264 264
265 return ic_data; 265 return ic_data;
266 } 266 }
267 267
268 268
269 static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
270 BinarySmiOpInstr* instr = d->AsBinarySmiOp();
271 if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
272 return instr;
273 }
274 return NULL;
275 }
276
277
278 static bool IsPositiveOrZeroSmiConst(Definition* d) {
279 ConstantInstr* const_instr = d->AsConstant();
280 if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
281 return Smi::Cast(const_instr->value()).Value() >= 0;
282 }
283 return false;
284 }
285
286
287 void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
288 Definition* bit_and_instr,
289 Definition* left_instr,
290 Definition* right_instr) {
291 ASSERT(bit_and_instr != NULL);
292 ASSERT((left_instr != NULL) && (right_instr != NULL));
293
294 // Check for pattern, smi_shift_left must be single-use.
295 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
296 if (!is_positive_or_zero) {
297 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
298 }
299 if (!is_positive_or_zero) return;
300
301 BinarySmiOpInstr* smi_shift_left = NULL;
302 if (bit_and_instr->InputAt(0)->IsSingleUse()) {
303 smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
304 }
305 if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
306 smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
307 }
308 if (smi_shift_left == NULL) return;
309
310 // Pattern recognized.
311 smi_shift_left->mark_truncating();
312 ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
313 if (bit_and_instr->IsBinaryMintOp()) {
314 // Replace Mint op with Smi op.
315 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
316 Token::kBIT_AND,
317 new(Z) Value(left_instr),
318 new(Z) Value(right_instr),
319 Thread::kNoDeoptId); // BIT_AND cannot deoptimize.
320 bit_and_instr->ReplaceWith(smi_op, current_iterator());
321 }
322 }
323
324
325 void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
326 intptr_t index,
327 Representation rep,
328 intptr_t cid) {
329 ExtractNthOutputInstr* extract =
330 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
331 instr->ReplaceUsesWith(extract);
332 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
333 }
334
335
336 // Dart:
337 // var x = d % 10;
338 // var y = d ~/ 10;
339 // var z = x + y;
340 //
341 // IL:
342 // v4 <- %(v2, v3)
343 // v5 <- ~/(v2, v3)
344 // v6 <- +(v4, v5)
345 //
346 // IL optimized:
347 // v4 <- DIVMOD(v2, v3);
348 // v5 <- LoadIndexed(v4, 0); // ~/ result
349 // v6 <- LoadIndexed(v4, 1); // % result
350 // v7 <- +(v5, v6)
351 // Because of the environment it is important that merged instruction replaces
352 // first original instruction encountered.
353 void AotOptimizer::TryMergeTruncDivMod(
354 GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
355 if (merge_candidates->length() < 2) {
356 // Need at least a TRUNCDIV and a MOD.
357 return;
358 }
359 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
360 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
361 if (curr_instr == NULL) {
362 // Instruction was merged already.
363 continue;
364 }
365 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
366 (curr_instr->op_kind() == Token::kMOD));
367 // Check if there is kMOD/kTRUNDIV binop with same inputs.
368 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
369 Token::kMOD : Token::kTRUNCDIV;
370 Definition* left_def = curr_instr->left()->definition();
371 Definition* right_def = curr_instr->right()->definition();
372 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
373 BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
374 // 'other_binop' can be NULL if it was already merged.
375 if ((other_binop != NULL) &&
376 (other_binop->op_kind() == other_kind) &&
377 (other_binop->left()->definition() == left_def) &&
378 (other_binop->right()->definition() == right_def)) {
379 (*merge_candidates)[k] = NULL; // Clear it.
380 ASSERT(curr_instr->HasUses());
381 AppendExtractNthOutputForMerged(
382 curr_instr,
383 MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
384 kTagged, kSmiCid);
385 ASSERT(other_binop->HasUses());
386 AppendExtractNthOutputForMerged(
387 other_binop,
388 MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
389 kTagged, kSmiCid);
390
391 ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
392 args->Add(new(Z) Value(curr_instr->left()->definition()));
393 args->Add(new(Z) Value(curr_instr->right()->definition()));
394
395 // Replace with TruncDivMod.
396 MergedMathInstr* div_mod = new(Z) MergedMathInstr(
397 args,
398 curr_instr->deopt_id(),
399 MergedMathInstr::kTruncDivMod);
400 curr_instr->ReplaceWith(div_mod, current_iterator());
401 other_binop->ReplaceUsesWith(div_mod);
402 other_binop->RemoveFromGraph();
403 // Only one merge possible. Because canonicalization happens later,
404 // more candidates are possible.
405 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
406 break;
407 }
408 }
409 }
410 }
411
412
413 // Tries to merge MathUnary operations, in this case sinus and cosinus.
414 void AotOptimizer::TryMergeMathUnary(
415 GrowableArray<MathUnaryInstr*>* merge_candidates) {
416 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
417 !FLAG_merge_sin_cos) {
418 return;
419 }
420 if (merge_candidates->length() < 2) {
421 // Need at least a SIN and a COS.
422 return;
423 }
424 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
425 MathUnaryInstr* curr_instr = (*merge_candidates)[i];
426 if (curr_instr == NULL) {
427 // Instruction was merged already.
428 continue;
429 }
430 const intptr_t kind = curr_instr->kind();
431 ASSERT((kind == MathUnaryInstr::kSin) ||
432 (kind == MathUnaryInstr::kCos));
433 // Check if there is sin/cos binop with same inputs.
434 const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
435 MathUnaryInstr::kCos : MathUnaryInstr::kSin;
436 Definition* def = curr_instr->value()->definition();
437 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
438 MathUnaryInstr* other_op = (*merge_candidates)[k];
439 // 'other_op' can be NULL if it was already merged.
440 if ((other_op != NULL) && (other_op->kind() == other_kind) &&
441 (other_op->value()->definition() == def)) {
442 (*merge_candidates)[k] = NULL; // Clear it.
443 ASSERT(curr_instr->HasUses());
444 AppendExtractNthOutputForMerged(curr_instr,
445 MergedMathInstr::OutputIndexOf(kind),
446 kUnboxedDouble, kDoubleCid);
447 ASSERT(other_op->HasUses());
448 AppendExtractNthOutputForMerged(
449 other_op,
450 MergedMathInstr::OutputIndexOf(other_kind),
451 kUnboxedDouble, kDoubleCid);
452 ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
453 args->Add(new(Z) Value(curr_instr->value()->definition()));
454 // Replace with SinCos.
455 MergedMathInstr* sin_cos =
456 new(Z) MergedMathInstr(args,
457 curr_instr->DeoptimizationTarget(),
458 MergedMathInstr::kSinCos);
459 curr_instr->ReplaceWith(sin_cos, current_iterator());
460 other_op->ReplaceUsesWith(sin_cos);
461 other_op->RemoveFromGraph();
462 // Only one merge possible. Because canonicalization happens later,
463 // more candidates are possible.
464 // TODO(srdjan): Allow merging of sin/cos into sincos.
465 break;
466 }
467 }
468 }
469 }
470
471
472 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
473 // shift can be a truncating Smi shift-left and result is always Smi.
474 // Merging occurs only per basic-block.
475 void AotOptimizer::TryOptimizePatterns() {
476 if (!FLAG_truncating_left_shift) return;
477 ASSERT(current_iterator_ == NULL);
478 GrowableArray<BinarySmiOpInstr*> div_mod_merge;
479 GrowableArray<MathUnaryInstr*> sin_cos_merge;
480 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
481 !block_it.Done();
482 block_it.Advance()) {
483 // Merging only per basic-block.
484 div_mod_merge.Clear();
485 sin_cos_merge.Clear();
486 ForwardInstructionIterator it(block_it.Current());
487 current_iterator_ = &it;
488 for (; !it.Done(); it.Advance()) {
489 if (it.Current()->IsBinarySmiOp()) {
490 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
491 if (binop->op_kind() == Token::kBIT_AND) {
492 OptimizeLeftShiftBitAndSmiOp(binop,
493 binop->left()->definition(),
494 binop->right()->definition());
495 } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
496 (binop->op_kind() == Token::kMOD)) {
497 if (binop->HasUses()) {
498 div_mod_merge.Add(binop);
499 }
500 }
501 } else if (it.Current()->IsBinaryMintOp()) {
502 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
503 if (mintop->op_kind() == Token::kBIT_AND) {
504 OptimizeLeftShiftBitAndSmiOp(mintop,
505 mintop->left()->definition(),
506 mintop->right()->definition());
507 }
508 } else if (it.Current()->IsMathUnary()) {
509 MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
510 if ((math_unary->kind() == MathUnaryInstr::kSin) ||
511 (math_unary->kind() == MathUnaryInstr::kCos)) {
512 if (math_unary->HasUses()) {
513 sin_cos_merge.Add(math_unary);
514 }
515 }
516 }
517 }
518 TryMergeTruncDivMod(&div_mod_merge);
519 TryMergeMathUnary(&sin_cos_merge);
520 current_iterator_ = NULL;
521 }
522 }
523
524
525 static bool ClassIdIsOneOf(intptr_t class_id, 269 static bool ClassIdIsOneOf(intptr_t class_id,
526 const GrowableArray<intptr_t>& class_ids) { 270 const GrowableArray<intptr_t>& class_ids) {
527 for (intptr_t i = 0; i < class_ids.length(); i++) { 271 for (intptr_t i = 0; i < class_ids.length(); i++) {
528 ASSERT(class_ids[i] != kIllegalCid); 272 ASSERT(class_ids[i] != kIllegalCid);
529 if (class_ids[i] == class_id) { 273 if (class_ids[i] == class_id) {
530 return true; 274 return true;
531 } 275 }
532 } 276 }
533 return false; 277 return false;
534 } 278 }
(...skipping 1993 matching lines...) Expand 10 before | Expand all | Expand 10 after
2528 flow_graph_->InsertBefore(check, new_check, 2272 flow_graph_->InsertBefore(check, new_check,
2529 check->env(), FlowGraph::kEffect); 2273 check->env(), FlowGraph::kEffect);
2530 current_iterator()->RemoveCurrentFromGraph(); 2274 current_iterator()->RemoveCurrentFromGraph();
2531 } 2275 }
2532 } 2276 }
2533 } 2277 }
2534 } 2278 }
2535 2279
2536 2280
2537 } // namespace dart 2281 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/compiler.cc » ('j') | runtime/vm/flow_graph.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698