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

Side by Side Diff: runtime/vm/jit_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: fix comment 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
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/precompiler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/jit_optimizer.h" 5 #include "vm/jit_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 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 const bool complete = false; 254 const bool complete = false;
255 PolymorphicInstanceCallInstr* specialized = 255 PolymorphicInstanceCallInstr* specialized =
256 new(Z) PolymorphicInstanceCallInstr(call->instance_call(), 256 new(Z) PolymorphicInstanceCallInstr(call->instance_call(),
257 ic_data, 257 ic_data,
258 with_checks, 258 with_checks,
259 complete); 259 complete);
260 call->ReplaceWith(specialized, current_iterator()); 260 call->ReplaceWith(specialized, current_iterator());
261 } 261 }
262 262
263 263
264 static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
265 BinarySmiOpInstr* instr = d->AsBinarySmiOp();
266 if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
267 return instr;
268 }
269 return NULL;
270 }
271
272
273 static bool IsPositiveOrZeroSmiConst(Definition* d) {
274 ConstantInstr* const_instr = d->AsConstant();
275 if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
276 return Smi::Cast(const_instr->value()).Value() >= 0;
277 }
278 return false;
279 }
280
281
282 void JitOptimizer::OptimizeLeftShiftBitAndSmiOp(
283 Definition* bit_and_instr,
284 Definition* left_instr,
285 Definition* right_instr) {
286 ASSERT(bit_and_instr != NULL);
287 ASSERT((left_instr != NULL) && (right_instr != NULL));
288
289 // Check for pattern, smi_shift_left must be single-use.
290 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
291 if (!is_positive_or_zero) {
292 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
293 }
294 if (!is_positive_or_zero) return;
295
296 BinarySmiOpInstr* smi_shift_left = NULL;
297 if (bit_and_instr->InputAt(0)->IsSingleUse()) {
298 smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
299 }
300 if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
301 smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
302 }
303 if (smi_shift_left == NULL) return;
304
305 // Pattern recognized.
306 smi_shift_left->mark_truncating();
307 ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
308 if (bit_and_instr->IsBinaryMintOp()) {
309 // Replace Mint op with Smi op.
310 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
311 Token::kBIT_AND,
312 new(Z) Value(left_instr),
313 new(Z) Value(right_instr),
314 Thread::kNoDeoptId); // BIT_AND cannot deoptimize.
315 bit_and_instr->ReplaceWith(smi_op, current_iterator());
316 }
317 }
318
319
320 void JitOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
321 intptr_t index,
322 Representation rep,
323 intptr_t cid) {
324 ExtractNthOutputInstr* extract =
325 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
326 instr->ReplaceUsesWith(extract);
327 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
328 }
329
330
331 // Dart:
332 // var x = d % 10;
333 // var y = d ~/ 10;
334 // var z = x + y;
335 //
336 // IL:
337 // v4 <- %(v2, v3)
338 // v5 <- ~/(v2, v3)
339 // v6 <- +(v4, v5)
340 //
341 // IL optimized:
342 // v4 <- DIVMOD(v2, v3);
343 // v5 <- LoadIndexed(v4, 0); // ~/ result
344 // v6 <- LoadIndexed(v4, 1); // % result
345 // v7 <- +(v5, v6)
346 // Because of the environment it is important that merged instruction replaces
347 // first original instruction encountered.
348 void JitOptimizer::TryMergeTruncDivMod(
349 GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
350 if (merge_candidates->length() < 2) {
351 // Need at least a TRUNCDIV and a MOD.
352 return;
353 }
354 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
355 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
356 if (curr_instr == NULL) {
357 // Instruction was merged already.
358 continue;
359 }
360 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
361 (curr_instr->op_kind() == Token::kMOD));
362 // Check if there is kMOD/kTRUNDIV binop with same inputs.
363 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
364 Token::kMOD : Token::kTRUNCDIV;
365 Definition* left_def = curr_instr->left()->definition();
366 Definition* right_def = curr_instr->right()->definition();
367 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
368 BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
369 // 'other_binop' can be NULL if it was already merged.
370 if ((other_binop != NULL) &&
371 (other_binop->op_kind() == other_kind) &&
372 (other_binop->left()->definition() == left_def) &&
373 (other_binop->right()->definition() == right_def)) {
374 (*merge_candidates)[k] = NULL; // Clear it.
375 ASSERT(curr_instr->HasUses());
376 AppendExtractNthOutputForMerged(
377 curr_instr,
378 MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
379 kTagged, kSmiCid);
380 ASSERT(other_binop->HasUses());
381 AppendExtractNthOutputForMerged(
382 other_binop,
383 MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
384 kTagged, kSmiCid);
385
386 ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
387 args->Add(new(Z) Value(curr_instr->left()->definition()));
388 args->Add(new(Z) Value(curr_instr->right()->definition()));
389
390 // Replace with TruncDivMod.
391 MergedMathInstr* div_mod = new(Z) MergedMathInstr(
392 args,
393 curr_instr->deopt_id(),
394 MergedMathInstr::kTruncDivMod);
395 curr_instr->ReplaceWith(div_mod, current_iterator());
396 other_binop->ReplaceUsesWith(div_mod);
397 other_binop->RemoveFromGraph();
398 // Only one merge possible. Because canonicalization happens later,
399 // more candidates are possible.
400 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
401 break;
402 }
403 }
404 }
405 }
406
407
408 // Tries to merge MathUnary operations, in this case sinus and cosinus.
409 void JitOptimizer::TryMergeMathUnary(
410 GrowableArray<MathUnaryInstr*>* merge_candidates) {
411 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
412 !FLAG_merge_sin_cos) {
413 return;
414 }
415 if (merge_candidates->length() < 2) {
416 // Need at least a SIN and a COS.
417 return;
418 }
419 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
420 MathUnaryInstr* curr_instr = (*merge_candidates)[i];
421 if (curr_instr == NULL) {
422 // Instruction was merged already.
423 continue;
424 }
425 const intptr_t kind = curr_instr->kind();
426 ASSERT((kind == MathUnaryInstr::kSin) ||
427 (kind == MathUnaryInstr::kCos));
428 // Check if there is sin/cos binop with same inputs.
429 const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
430 MathUnaryInstr::kCos : MathUnaryInstr::kSin;
431 Definition* def = curr_instr->value()->definition();
432 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
433 MathUnaryInstr* other_op = (*merge_candidates)[k];
434 // 'other_op' can be NULL if it was already merged.
435 if ((other_op != NULL) && (other_op->kind() == other_kind) &&
436 (other_op->value()->definition() == def)) {
437 (*merge_candidates)[k] = NULL; // Clear it.
438 ASSERT(curr_instr->HasUses());
439 AppendExtractNthOutputForMerged(curr_instr,
440 MergedMathInstr::OutputIndexOf(kind),
441 kUnboxedDouble, kDoubleCid);
442 ASSERT(other_op->HasUses());
443 AppendExtractNthOutputForMerged(
444 other_op,
445 MergedMathInstr::OutputIndexOf(other_kind),
446 kUnboxedDouble, kDoubleCid);
447 ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
448 args->Add(new(Z) Value(curr_instr->value()->definition()));
449 // Replace with SinCos.
450 MergedMathInstr* sin_cos =
451 new(Z) MergedMathInstr(args,
452 curr_instr->DeoptimizationTarget(),
453 MergedMathInstr::kSinCos);
454 curr_instr->ReplaceWith(sin_cos, current_iterator());
455 other_op->ReplaceUsesWith(sin_cos);
456 other_op->RemoveFromGraph();
457 // Only one merge possible. Because canonicalization happens later,
458 // more candidates are possible.
459 // TODO(srdjan): Allow merging of sin/cos into sincos.
460 break;
461 }
462 }
463 }
464 }
465
466
467 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
468 // shift can be a truncating Smi shift-left and result is always Smi.
469 // Merging occurs only per basic-block.
470 void JitOptimizer::TryOptimizePatterns() {
471 if (!FLAG_truncating_left_shift) return;
472 ASSERT(current_iterator_ == NULL);
473 GrowableArray<BinarySmiOpInstr*> div_mod_merge;
474 GrowableArray<MathUnaryInstr*> sin_cos_merge;
475 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
476 !block_it.Done();
477 block_it.Advance()) {
478 // Merging only per basic-block.
479 div_mod_merge.Clear();
480 sin_cos_merge.Clear();
481 ForwardInstructionIterator it(block_it.Current());
482 current_iterator_ = &it;
483 for (; !it.Done(); it.Advance()) {
484 if (it.Current()->IsBinarySmiOp()) {
485 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
486 if (binop->op_kind() == Token::kBIT_AND) {
487 OptimizeLeftShiftBitAndSmiOp(binop,
488 binop->left()->definition(),
489 binop->right()->definition());
490 } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
491 (binop->op_kind() == Token::kMOD)) {
492 if (binop->HasUses()) {
493 div_mod_merge.Add(binop);
494 }
495 }
496 } else if (it.Current()->IsBinaryMintOp()) {
497 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
498 if (mintop->op_kind() == Token::kBIT_AND) {
499 OptimizeLeftShiftBitAndSmiOp(mintop,
500 mintop->left()->definition(),
501 mintop->right()->definition());
502 }
503 } else if (it.Current()->IsMathUnary()) {
504 MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
505 if ((math_unary->kind() == MathUnaryInstr::kSin) ||
506 (math_unary->kind() == MathUnaryInstr::kCos)) {
507 if (math_unary->HasUses()) {
508 sin_cos_merge.Add(math_unary);
509 }
510 }
511 }
512 }
513 TryMergeTruncDivMod(&div_mod_merge);
514 TryMergeMathUnary(&sin_cos_merge);
515 current_iterator_ = NULL;
516 }
517 }
518
519
520 static bool ClassIdIsOneOf(intptr_t class_id, 264 static bool ClassIdIsOneOf(intptr_t class_id,
521 const GrowableArray<intptr_t>& class_ids) { 265 const GrowableArray<intptr_t>& class_ids) {
522 for (intptr_t i = 0; i < class_ids.length(); i++) { 266 for (intptr_t i = 0; i < class_ids.length(); i++) {
523 ASSERT(class_ids[i] != kIllegalCid); 267 ASSERT(class_ids[i] != kIllegalCid);
524 if (class_ids[i] == class_id) { 268 if (class_ids[i] == class_id) {
525 return true; 269 return true;
526 } 270 }
527 } 271 }
528 return false; 272 return false;
529 } 273 }
(...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after
1331 for (Value::Iterator it(load->input_use_list()); 1075 for (Value::Iterator it(load->input_use_list());
1332 !it.Done(); 1076 !it.Done();
1333 it.Advance()) { 1077 it.Advance()) {
1334 it.Current()->SetReachingType(NULL); 1078 it.Current()->SetReachingType(NULL);
1335 } 1079 }
1336 } 1080 }
1337 return true; 1081 return true;
1338 } 1082 }
1339 1083
1340 1084
1341 bool JitOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
1342 MethodRecognizer::Kind getter) {
1343 if (!ShouldInlineSimd()) {
1344 return false;
1345 }
1346 AddCheckClass(call->ArgumentAt(0),
1347 ICData::ZoneHandle(
1348 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1349 call->deopt_id(),
1350 call->env(),
1351 call);
1352 if ((getter == MethodRecognizer::kFloat64x2GetX) ||
1353 (getter == MethodRecognizer::kFloat64x2GetY)) {
1354 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
1355 getter,
1356 new(Z) Value(call->ArgumentAt(0)),
1357 0,
1358 call->deopt_id());
1359 ReplaceCall(call, instr);
1360 return true;
1361 }
1362 UNREACHABLE();
1363 return false;
1364 }
1365
1366
1367 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, 1085 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
1368 Token::Kind op_kind) { 1086 Token::Kind op_kind) {
1369 if (!ShouldInlineSimd()) { 1087 if (!ShouldInlineSimd()) {
1370 return false; 1088 return false;
1371 } 1089 }
1372 ASSERT(call->ArgumentCount() == 2); 1090 ASSERT(call->ArgumentCount() == 2);
1373 Definition* left = call->ArgumentAt(0); 1091 Definition* left = call->ArgumentAt(0);
1374 Definition* right = call->ArgumentAt(1); 1092 Definition* right = call->ArgumentAt(1);
1375 // Type check left. 1093 // Type check left.
1376 AddCheckClass(left, 1094 AddCheckClass(left,
(...skipping 1070 matching lines...) Expand 10 before | Expand all | Expand 10 after
2447 2165
2448 // Discard the environment from the original instruction because the store 2166 // Discard the environment from the original instruction because the store
2449 // can't deoptimize. 2167 // can't deoptimize.
2450 instr->RemoveEnvironment(); 2168 instr->RemoveEnvironment();
2451 ReplaceCall(instr, store); 2169 ReplaceCall(instr, store);
2452 return true; 2170 return true;
2453 } 2171 }
2454 2172
2455 2173
2456 } // namespace dart 2174 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/precompiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698