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

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

Issue 10912094: Reapply "Remove classes Computation and BindInstr." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/il_printer.h » ('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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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/cha.h" 7 #include "vm/cha.h"
8 #include "vm/flow_graph_builder.h" 8 #include "vm/flow_graph_builder.h"
9 #include "vm/hash_map.h" 9 #include "vm/hash_map.h"
10 #include "vm/il_printer.h" 10 #include "vm/il_printer.h"
(...skipping 13 matching lines...) Expand all
24 void FlowGraphOptimizer::ApplyICData() { 24 void FlowGraphOptimizer::ApplyICData() {
25 VisitBlocks(); 25 VisitBlocks();
26 } 26 }
27 27
28 28
29 void FlowGraphOptimizer::OptimizeComputations() { 29 void FlowGraphOptimizer::OptimizeComputations() {
30 for (intptr_t i = 0; i < block_order_.length(); ++i) { 30 for (intptr_t i = 0; i < block_order_.length(); ++i) {
31 BlockEntryInstr* entry = block_order_[i]; 31 BlockEntryInstr* entry = block_order_[i];
32 entry->Accept(this); 32 entry->Accept(this);
33 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { 33 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
34 BindInstr* instr = it.Current()->AsBind(); 34 Definition* defn = it.Current()->AsDefinition();
35 if (instr != NULL) { 35 if (defn != NULL) {
36 Definition* result = instr->computation()->TryReplace(instr); 36 Definition* result = defn->Canonicalize();
37 if (result != instr) { 37 if (result != defn) {
38 if (result != NULL) { 38 if (result != NULL) {
39 instr->ReplaceUsesWith(result); 39 defn->ReplaceUsesWith(result);
40 if (FLAG_trace_optimization) { 40 if (FLAG_trace_optimization) {
41 OS::Print("Replacing v%d with v%d\n", 41 OS::Print("Replacing v%d with v%d\n",
42 instr->ssa_temp_index(), 42 defn->ssa_temp_index(),
43 result->ssa_temp_index()); 43 result->ssa_temp_index());
44 } 44 }
45 } else if (FLAG_trace_optimization) { 45 } else if (FLAG_trace_optimization) {
46 OS::Print("Removing v%d.\n", instr->ssa_temp_index()); 46 OS::Print("Removing v%d.\n", defn->ssa_temp_index());
47 } 47 }
48 it.RemoveCurrentFromGraph(); 48 it.RemoveCurrentFromGraph();
49 } 49 }
50 } 50 }
51 } 51 }
52 } 52 }
53 } 53 }
54 54
55 55
56 static Computation* CreateConversion(Representation from, 56 static Definition* CreateConversion(Representation from,
57 Representation to, 57 Representation to,
58 Definition* def, 58 Definition* def,
59 Instruction* deopt_target) { 59 Instruction* deopt_target) {
60 if ((from == kUnboxedDouble) && (to == kTagged)) { 60 if ((from == kUnboxedDouble) && (to == kTagged)) {
61 return new BoxDoubleComp(new Value(def), NULL); 61 return new BoxDoubleInstr(new Value(def), NULL);
62 } else if ((from == kTagged) && (to == kUnboxedDouble)) { 62 } else if ((from == kTagged) && (to == kUnboxedDouble)) {
63 const intptr_t deopt_id = (deopt_target != NULL) ? 63 const intptr_t deopt_id = (deopt_target != NULL) ?
64 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; 64 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
65 ASSERT((deopt_target != NULL) || (def->GetPropagatedCid() == kDoubleCid)); 65 ASSERT((deopt_target != NULL) || (def->GetPropagatedCid() == kDoubleCid));
66 return new UnboxDoubleComp(new Value(def), deopt_id); 66 return new UnboxDoubleInstr(new Value(def), deopt_id);
67 } else { 67 } else {
68 UNREACHABLE(); 68 UNREACHABLE();
69 return NULL; 69 return NULL;
70 } 70 }
71 } 71 }
72 72
73 73
74 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { 74 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) {
75 const Representation from_rep = def->representation(); 75 const Representation from_rep = def->representation();
76 76
(...skipping 12 matching lines...) Expand all
89 if (!instr->AsPhi()->is_alive()) continue; 89 if (!instr->AsPhi()->is_alive()) continue;
90 90
91 // For phis conversions have to be inserted in the predecessor. 91 // For phis conversions have to be inserted in the predecessor.
92 const BlockEntryInstr* pred = 92 const BlockEntryInstr* pred =
93 instr->AsPhi()->block()->PredecessorAt(use->use_index()); 93 instr->AsPhi()->block()->PredecessorAt(use->use_index());
94 instr = pred->last_instruction(); 94 instr = pred->last_instruction();
95 } else { 95 } else {
96 deopt_target = instr; 96 deopt_target = instr;
97 } 97 }
98 98
99 BindInstr* converted = InsertBefore( 99 Definition* converted =
100 instr, 100 CreateConversion(from_rep, to_rep, def, deopt_target);
101 CreateConversion(from_rep, to_rep, def, deopt_target), 101 InsertBefore(instr, converted, use->instruction()->env(),
102 use->instruction()->env(), 102 Definition::kValue);
103 Definition::kValue);
104
105 use->set_definition(converted); 103 use->set_definition(converted);
106 } 104 }
107 } 105 }
108 106
107
109 void FlowGraphOptimizer::SelectRepresentations() { 108 void FlowGraphOptimizer::SelectRepresentations() {
110 // Convervatively unbox all phis that were proven to be of type Double. 109 // Convervatively unbox all phis that were proven to be of type Double.
111 for (intptr_t i = 0; i < block_order_.length(); ++i) { 110 for (intptr_t i = 0; i < block_order_.length(); ++i) {
112 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); 111 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry();
113 if (join_entry == NULL) continue; 112 if (join_entry == NULL) continue;
114 113
115 if (join_entry->phis() != NULL) { 114 if (join_entry->phis() != NULL) {
116 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { 115 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
117 PhiInstr* phi = (*join_entry->phis())[i]; 116 PhiInstr* phi = (*join_entry->phis())[i];
118 if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) { 117 if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) {
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 (class_ids[0] == kDoubleCid) || (class_ids[1] == kDoubleCid); 256 (class_ids[0] == kDoubleCid) || (class_ids[1] == kDoubleCid);
258 257
259 const bool seen_only_smi_or_double = 258 const bool seen_only_smi_or_double =
260 ((class_ids[0] == kDoubleCid) || (class_ids[0] == kSmiCid)) && 259 ((class_ids[0] == kDoubleCid) || (class_ids[0] == kSmiCid)) &&
261 ((class_ids[1] == kDoubleCid) || (class_ids[1] == kSmiCid)); 260 ((class_ids[1] == kDoubleCid) || (class_ids[1] == kSmiCid));
262 261
263 return seen_double && seen_only_smi_or_double; 262 return seen_double && seen_only_smi_or_double;
264 } 263 }
265 264
266 265
267 static void RemovePushArguments(InstanceCallComp* comp) { 266 static void RemovePushArguments(InstanceCallInstr* call) {
268 // Remove original push arguments. 267 // Remove original push arguments.
269 for (intptr_t i = 0; i < comp->ArgumentCount(); ++i) { 268 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
270 PushArgumentInstr* push = comp->ArgumentAt(i); 269 PushArgumentInstr* push = call->ArgumentAt(i);
271 push->ReplaceUsesWith(push->value()->definition()); 270 push->ReplaceUsesWith(push->value()->definition());
272 push->RemoveFromGraph(); 271 push->RemoveFromGraph();
273 } 272 }
274 } 273 }
275 274
276 275
277 // Returns true if all targets are the same. 276 // Returns true if all targets are the same.
278 // TODO(srdjan): if targets are native use their C_function to compare. 277 // TODO(srdjan): if targets are native use their C_function to compare.
279 static bool HasOneTarget(const ICData& ic_data) { 278 static bool HasOneTarget(const ICData& ic_data) {
280 ASSERT(ic_data.NumberOfChecks() > 0); 279 ASSERT(ic_data.NumberOfChecks() > 0);
281 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0)); 280 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0));
282 Function& test_target = Function::Handle(); 281 Function& test_target = Function::Handle();
283 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { 282 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) {
284 test_target = ic_data.GetTargetAt(i); 283 test_target = ic_data.GetTargetAt(i);
285 if (first_target.raw() != test_target.raw()) { 284 if (first_target.raw() != test_target.raw()) {
286 return false; 285 return false;
287 } 286 }
288 } 287 }
289 return true; 288 return true;
290 } 289 }
291 290
292 291
293 static intptr_t ReceiverClassId(InstanceCallComp* comp) { 292 static intptr_t ReceiverClassId(InstanceCallInstr* call) {
294 if (!comp->HasICData()) return kIllegalCid; 293 if (!call->HasICData()) return kIllegalCid;
295 294
296 const ICData& ic_data = *comp->ic_data(); 295 const ICData& ic_data = *call->ic_data();
297 296
298 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; 297 if (ic_data.NumberOfChecks() == 0) return kIllegalCid;
299 // TODO(vegorov): Add multiple receiver type support. 298 // TODO(vegorov): Add multiple receiver type support.
300 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; 299 if (ic_data.NumberOfChecks() != 1) return kIllegalCid;
301 ASSERT(HasOneTarget(ic_data)); 300 ASSERT(HasOneTarget(ic_data));
302 301
303 Function& target = Function::Handle(); 302 Function& target = Function::Handle();
304 intptr_t class_id; 303 intptr_t class_id;
305 ic_data.GetOneClassCheckAt(0, &class_id, &target); 304 ic_data.GetOneClassCheckAt(0, &class_id, &target);
306 return class_id; 305 return class_id;
307 } 306 }
308 307
309 308
310 void FlowGraphOptimizer::AddCheckClass(BindInstr* instr, 309 void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call,
311 InstanceCallComp* comp,
312 Value* value) { 310 Value* value) {
313 // Type propagation has not run yet, we cannot eliminate the check. 311 // Type propagation has not run yet, we cannot eliminate the check.
314 const ICData& unary_checks = 312 const ICData& unary_checks =
315 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); 313 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
316 CheckClassComp* check = new CheckClassComp(value, comp, unary_checks); 314 CheckClassInstr* check = new CheckClassInstr(value, call, unary_checks);
317 InsertBefore(instr, check, instr->env(), Definition::kEffect); 315 InsertBefore(call, check, call->env(), Definition::kEffect);
318 } 316 }
319 317
320 318
321 bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, 319 bool FlowGraphOptimizer::TryReplaceWithArrayOp(InstanceCallInstr* call,
322 InstanceCallComp* comp,
323 Token::Kind op_kind) { 320 Token::Kind op_kind) {
324 // TODO(fschneider): Optimize []= operator in checked mode as well. 321 // TODO(fschneider): Optimize []= operator in checked mode as well.
325 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; 322 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false;
326 323
327 const intptr_t class_id = ReceiverClassId(comp); 324 const intptr_t class_id = ReceiverClassId(call);
328 switch (class_id) { 325 switch (class_id) {
329 case kImmutableArrayCid: 326 case kImmutableArrayCid:
330 // Stores are only specialized for Array and GrowableObjectArray, 327 // Stores are only specialized for Array and GrowableObjectArray,
331 // not for ImmutableArray. 328 // not for ImmutableArray.
332 if (op_kind == Token::kASSIGN_INDEX) return false; 329 if (op_kind == Token::kASSIGN_INDEX) return false;
333 // Fall through. 330 // Fall through.
334 case kArrayCid: 331 case kArrayCid:
335 case kGrowableObjectArrayCid: { 332 case kGrowableObjectArrayCid: {
336 Value* array = comp->ArgumentAt(0)->value(); 333 Value* array = call->ArgumentAt(0)->value();
337 Value* index = comp->ArgumentAt(1)->value(); 334 Value* index = call->ArgumentAt(1)->value();
338 // Insert class check and index smi checks and attach a copy of the 335 // Insert class check and index smi checks and attach a copy of the
339 // original environment because the operation can still deoptimize. 336 // original environment because the operation can still deoptimize.
340 AddCheckClass(instr, comp, array->Copy()); 337 AddCheckClass(call, array->Copy());
341 InsertBefore(instr, 338 InsertBefore(call,
342 new CheckSmiComp(index->Copy(), comp->deopt_id()), 339 new CheckSmiInstr(index->Copy(), call->deopt_id()),
343 instr->env(), 340 call->env(),
344 Definition::kEffect); 341 Definition::kEffect);
345 // Insert array bounds check. 342 // Insert array bounds check.
346 InsertBefore(instr, 343 InsertBefore(call,
347 new CheckArrayBoundComp(array->Copy(), 344 new CheckArrayBoundInstr(array->Copy(),
348 index->Copy(), 345 index->Copy(),
349 class_id, 346 class_id,
350 comp), 347 call),
351 instr->env(), 348 call->env(),
352 Definition::kEffect); 349 Definition::kEffect);
353 Computation* array_op = NULL; 350 Definition* array_op = NULL;
354 if (op_kind == Token::kINDEX) { 351 if (op_kind == Token::kINDEX) {
355 array_op = new LoadIndexedComp(array, index, class_id); 352 array_op = new LoadIndexedInstr(array, index, class_id);
356 } else { 353 } else {
357 Value* value = comp->ArgumentAt(2)->value(); 354 Value* value = call->ArgumentAt(2)->value();
358 array_op = new StoreIndexedComp(array, index, value, class_id); 355 array_op = new StoreIndexedInstr(array, index, value, class_id);
359 } 356 }
360 instr->set_computation(array_op); 357 call->ReplaceWith(array_op, current_iterator());
361 RemovePushArguments(comp); 358 RemovePushArguments(call);
362 return true; 359 return true;
363 } 360 }
364 default: 361 default:
365 return false; 362 return false;
366 } 363 }
367 } 364 }
368 365
369 366
370 BindInstr* FlowGraphOptimizer::InsertBefore(Instruction* instr, 367 void FlowGraphOptimizer::InsertBefore(Instruction* instr,
371 Computation* comp, 368 Definition* defn,
372 Environment* env, 369 Environment* env,
373 BindInstr::UseKind use_kind) { 370 Definition::UseKind use_kind) {
374 BindInstr* bind = new BindInstr(use_kind, comp); 371 if (env != NULL) env->CopyTo(defn);
375 if (env != NULL) env->CopyTo(bind);
376 if (use_kind == Definition::kValue) { 372 if (use_kind == Definition::kValue) {
377 bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); 373 defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
378 } 374 }
379 bind->InsertBefore(instr); 375 defn->InsertBefore(instr);
380 return bind;
381 } 376 }
382 377
383 378
384 BindInstr* FlowGraphOptimizer::InsertAfter(Instruction* instr, 379 void FlowGraphOptimizer::InsertAfter(Instruction* instr,
385 Computation* comp, 380 Definition* defn,
386 Environment* env, 381 Environment* env,
387 BindInstr::UseKind use_kind) { 382 Definition::UseKind use_kind) {
388 BindInstr* bind = new BindInstr(use_kind, comp); 383 if (env != NULL) env->CopyTo(defn);
389 if (env != NULL) env->CopyTo(bind);
390 if (use_kind == Definition::kValue) { 384 if (use_kind == Definition::kValue) {
391 bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); 385 defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
392 } 386 }
393 bind->InsertAfter(instr); 387 defn->InsertAfter(instr);
394 return bind;
395 } 388 }
396 389
397 390
398 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, 391 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
399 InstanceCallComp* comp,
400 Token::Kind op_kind) { 392 Token::Kind op_kind) {
401 intptr_t operands_type = kIllegalCid; 393 intptr_t operands_type = kIllegalCid;
402 ASSERT(comp->HasICData()); 394 ASSERT(call->HasICData());
403 const ICData& ic_data = *comp->ic_data(); 395 const ICData& ic_data = *call->ic_data();
404 switch (op_kind) { 396 switch (op_kind) {
405 case Token::kADD: 397 case Token::kADD:
406 case Token::kSUB: 398 case Token::kSUB:
407 case Token::kMUL: 399 case Token::kMUL:
408 if (HasOnlyTwoSmi(ic_data)) { 400 if (HasOnlyTwoSmi(ic_data)) {
409 operands_type = kSmiCid; 401 operands_type = kSmiCid;
410 } else if (ShouldSpecializeForDouble(ic_data)) { 402 } else if (ShouldSpecializeForDouble(ic_data)) {
411 operands_type = kDoubleCid; 403 operands_type = kDoubleCid;
412 } else { 404 } else {
413 return false; 405 return false;
(...skipping 26 matching lines...) Expand all
440 if (HasOnlyTwoSmi(ic_data)) { 432 if (HasOnlyTwoSmi(ic_data)) {
441 operands_type = kSmiCid; 433 operands_type = kSmiCid;
442 } else { 434 } else {
443 return false; 435 return false;
444 } 436 }
445 break; 437 break;
446 default: 438 default:
447 UNREACHABLE(); 439 UNREACHABLE();
448 }; 440 };
449 441
450 ASSERT(comp->ArgumentCount() == 2); 442 ASSERT(call->ArgumentCount() == 2);
451 if (operands_type == kDoubleCid) { 443 if (operands_type == kDoubleCid) {
452 Value* left = comp->ArgumentAt(0)->value(); 444 Value* left = call->ArgumentAt(0)->value();
453 Value* right = comp->ArgumentAt(1)->value(); 445 Value* right = call->ArgumentAt(1)->value();
454 446
455 // Check that either left or right are not a smi. Result or a 447 // Check that either left or right are not a smi. Result or a
456 // binary operation with two smis is a smi not a double. 448 // binary operation with two smis is a smi not a double.
457 InsertBefore(instr, 449 InsertBefore(call,
458 new CheckEitherNonSmiComp(left->Copy(), 450 new CheckEitherNonSmiInstr(left->Copy(),
459 right->Copy(), 451 right->Copy(),
460 comp), 452 call),
461 instr->env(), 453 call->env(),
462 Definition::kEffect); 454 Definition::kEffect);
463 455
464 UnboxedDoubleBinaryOpComp* double_bin_op = 456 UnboxedDoubleBinaryOpInstr* double_bin_op =
465 new UnboxedDoubleBinaryOpComp(op_kind, 457 new UnboxedDoubleBinaryOpInstr(op_kind,
466 left->Copy(), 458 left->Copy(),
467 right->Copy(), 459 right->Copy(),
468 comp); 460 call);
469 instr->set_computation(double_bin_op); 461 call->ReplaceWith(double_bin_op, current_iterator());
470 462 RemovePushArguments(call);
471 RemovePushArguments(comp);
472 } else if (operands_type == kMintCid) { 463 } else if (operands_type == kMintCid) {
473 Value* left = comp->ArgumentAt(0)->value(); 464 Value* left = call->ArgumentAt(0)->value();
474 Value* right = comp->ArgumentAt(1)->value(); 465 Value* right = call->ArgumentAt(1)->value();
475 BinaryMintOpComp* bin_op = new BinaryMintOpComp(op_kind, 466 BinaryMintOpInstr* bin_op = new BinaryMintOpInstr(op_kind,
476 comp, 467 call,
477 left, 468 left,
478 right); 469 right);
479 instr->set_computation(bin_op); 470 call->ReplaceWith(bin_op, current_iterator());
480 RemovePushArguments(comp); 471 RemovePushArguments(call);
481 } else { 472 } else {
482 ASSERT(operands_type == kSmiCid); 473 ASSERT(operands_type == kSmiCid);
483 Value* left = comp->ArgumentAt(0)->value(); 474 Value* left = call->ArgumentAt(0)->value();
484 Value* right = comp->ArgumentAt(1)->value(); 475 Value* right = call->ArgumentAt(1)->value();
485 // Insert two smi checks and attach a copy of the original 476 // Insert two smi checks and attach a copy of the original
486 // environment because the smi operation can still deoptimize. 477 // environment because the smi operation can still deoptimize.
487 InsertBefore(instr, 478 InsertBefore(call,
488 new CheckSmiComp(left->Copy(), comp->deopt_id()), 479 new CheckSmiInstr(left->Copy(), call->deopt_id()),
489 instr->env(), 480 call->env(),
490 Definition::kEffect); 481 Definition::kEffect);
491 InsertBefore(instr, 482 InsertBefore(call,
492 new CheckSmiComp(right->Copy(), comp->deopt_id()), 483 new CheckSmiInstr(right->Copy(), call->deopt_id()),
493 instr->env(), 484 call->env(),
494 Definition::kEffect); 485 Definition::kEffect);
495 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, 486 BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right);
496 comp, 487 call->ReplaceWith(bin_op, current_iterator());
497 left, 488 RemovePushArguments(call);
498 right);
499 instr->set_computation(bin_op);
500 RemovePushArguments(comp);
501 } 489 }
502 return true; 490 return true;
503 } 491 }
504 492
505 493
506 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, 494 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
507 InstanceCallComp* comp,
508 Token::Kind op_kind) { 495 Token::Kind op_kind) {
509 if (comp->ic_data()->NumberOfChecks() != 1) { 496 if (call->ic_data()->NumberOfChecks() != 1) {
510 // TODO(srdjan): Not yet supported. 497 // TODO(srdjan): Not yet supported.
511 return false; 498 return false;
512 } 499 }
513 ASSERT(comp->ArgumentCount() == 1); 500 ASSERT(call->ArgumentCount() == 1);
514 Computation* unary_op = NULL; 501 Definition* unary_op = NULL;
515 if (HasOneSmi(*comp->ic_data())) { 502 if (HasOneSmi(*call->ic_data())) {
516 Value* value = comp->ArgumentAt(0)->value(); 503 Value* value = call->ArgumentAt(0)->value();
517 InsertBefore(instr, 504 InsertBefore(call,
518 new CheckSmiComp(value->Copy(), comp->deopt_id()), 505 new CheckSmiInstr(value->Copy(), call->deopt_id()),
519 instr->env(), 506 call->env(),
520 Definition::kEffect); 507 Definition::kEffect);
521 unary_op = new UnarySmiOpComp(op_kind, 508 unary_op = new UnarySmiOpInstr(op_kind,
522 (op_kind == Token::kNEGATE) ? comp : NULL, 509 (op_kind == Token::kNEGATE) ? call : NULL,
523 value); 510 value);
524 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { 511 } else if (HasOneDouble(*call->ic_data()) && (op_kind == Token::kNEGATE)) {
525 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); 512 unary_op = new NumberNegateInstr(call, call->ArgumentAt(0)->value());
526 } 513 }
527 if (unary_op == NULL) return false; 514 if (unary_op == NULL) return false;
528 515
529 instr->set_computation(unary_op); 516 call->ReplaceWith(unary_op, current_iterator());
530 RemovePushArguments(comp); 517 RemovePushArguments(call);
531 return true; 518 return true;
532 } 519 }
533 520
534 521
535 // Using field class 522 // Using field class
536 static RawField* GetField(intptr_t class_id, const String& field_name) { 523 static RawField* GetField(intptr_t class_id, const String& field_name) {
537 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); 524 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id));
538 Field& field = Field::Handle(); 525 Field& field = Field::Handle();
539 while (!cls.IsNull()) { 526 while (!cls.IsNull()) {
540 field = cls.LookupInstanceField(field_name); 527 field = cls.LookupInstanceField(field_name);
541 if (!field.IsNull()) { 528 if (!field.IsNull()) {
542 return field.raw(); 529 return field.raw();
543 } 530 }
544 cls = cls.SuperClass(); 531 cls = cls.SuperClass();
545 } 532 }
546 return Field::null(); 533 return Field::null();
547 } 534 }
548 535
549 536
550 // Only unique implicit instance getters can be currently handled. 537 // Only unique implicit instance getters can be currently handled.
551 bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, 538 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
552 InstanceCallComp* comp) { 539 ASSERT(call->HasICData());
553 ASSERT(comp->HasICData()); 540 const ICData& ic_data = *call->ic_data();
554 const ICData& ic_data = *comp->ic_data();
555 if (ic_data.NumberOfChecks() == 0) { 541 if (ic_data.NumberOfChecks() == 0) {
556 // No type feedback collected. 542 // No type feedback collected.
557 return false; 543 return false;
558 } 544 }
559 Function& target = Function::Handle(); 545 Function& target = Function::Handle();
560 GrowableArray<intptr_t> class_ids; 546 GrowableArray<intptr_t> class_ids;
561 ic_data.GetCheckAt(0, &class_ids, &target); 547 ic_data.GetCheckAt(0, &class_ids, &target);
562 ASSERT(class_ids.length() == 1); 548 ASSERT(class_ids.length() == 1);
563 549
564 if (target.kind() == RawFunction::kImplicitGetter) { 550 if (target.kind() == RawFunction::kImplicitGetter) {
565 if (!HasOneTarget(ic_data)) { 551 if (!HasOneTarget(ic_data)) {
566 // TODO(srdjan): Implement for mutiple targets. 552 // TODO(srdjan): Implement for mutiple targets.
567 return false; 553 return false;
568 } 554 }
569 // Inline implicit instance getter. 555 // Inline implicit instance getter.
570 const String& field_name = 556 const String& field_name =
571 String::Handle(Field::NameFromGetter(comp->function_name())); 557 String::Handle(Field::NameFromGetter(call->function_name()));
572 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); 558 const Field& field = Field::Handle(GetField(class_ids[0], field_name));
573 ASSERT(!field.IsNull()); 559 ASSERT(!field.IsNull());
574 560
575 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); 561 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
576 // Detach environment from the original instruction because it can't 562 // Detach environment from the original instruction because it can't
577 // deoptimize. 563 // deoptimize.
578 instr->set_env(NULL); 564 call->set_env(NULL);
579 LoadInstanceFieldComp* load = 565 LoadInstanceFieldInstr* load =
580 new LoadInstanceFieldComp(field, comp->ArgumentAt(0)->value()); 566 new LoadInstanceFieldInstr(field, call->ArgumentAt(0)->value());
581 instr->set_computation(load); 567 call->ReplaceWith(load, current_iterator());
582 RemovePushArguments(comp); 568 RemovePushArguments(call);
583 return true; 569 return true;
584 } 570 }
585 571
586 // Not an implicit getter. 572 // Not an implicit getter.
587 MethodRecognizer::Kind recognized_kind = 573 MethodRecognizer::Kind recognized_kind =
588 MethodRecognizer::RecognizeKind(target); 574 MethodRecognizer::RecognizeKind(target);
589 575
590 // VM objects length getter. 576 // VM objects length getter.
591 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || 577 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) ||
592 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || 578 (recognized_kind == MethodRecognizer::kImmutableArrayLength) ||
593 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { 579 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) {
594 if (!HasOneTarget(ic_data)) { 580 if (!HasOneTarget(ic_data)) {
595 // TODO(srdjan): Implement for mutiple targets. 581 // TODO(srdjan): Implement for mutiple targets.
596 return false; 582 return false;
597 } 583 }
598 intptr_t length_offset = -1; 584 intptr_t length_offset = -1;
599 switch (recognized_kind) { 585 switch (recognized_kind) {
600 case MethodRecognizer::kObjectArrayLength: 586 case MethodRecognizer::kObjectArrayLength:
601 case MethodRecognizer::kImmutableArrayLength: 587 case MethodRecognizer::kImmutableArrayLength:
602 length_offset = Array::length_offset(); 588 length_offset = Array::length_offset();
603 break; 589 break;
604 case MethodRecognizer::kGrowableArrayLength: 590 case MethodRecognizer::kGrowableArrayLength:
605 length_offset = GrowableObjectArray::length_offset(); 591 length_offset = GrowableObjectArray::length_offset();
606 break; 592 break;
607 default: 593 default:
608 UNREACHABLE(); 594 UNREACHABLE();
609 } 595 }
610 // Check receiver class. 596 // Check receiver class.
611 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); 597 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
612 598
613 LoadVMFieldComp* load = new LoadVMFieldComp( 599 LoadVMFieldInstr* load = new LoadVMFieldInstr(
614 comp->ArgumentAt(0)->value(), 600 call->ArgumentAt(0)->value(),
615 length_offset, 601 length_offset,
616 Type::ZoneHandle(Type::SmiType())); 602 Type::ZoneHandle(Type::SmiType()));
617 load->set_result_cid(kSmiCid); 603 load->set_result_cid(kSmiCid);
618 instr->set_computation(load); 604 call->ReplaceWith(load, current_iterator());
619 RemovePushArguments(comp); 605 RemovePushArguments(call);
620 return true; 606 return true;
621 } 607 }
622 608
623 if (recognized_kind == MethodRecognizer::kStringBaseLength) { 609 if (recognized_kind == MethodRecognizer::kStringBaseLength) {
624 if (!HasOneTarget(ic_data)) { 610 if (!HasOneTarget(ic_data)) {
625 // Target is not only StringBase_get_length. 611 // Target is not only StringBase_get_length.
626 return false; 612 return false;
627 } 613 }
628 // Check receiver class. 614 // Check receiver class.
629 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); 615 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
630 616
631 LoadVMFieldComp* load = new LoadVMFieldComp( 617 LoadVMFieldInstr* load = new LoadVMFieldInstr(
632 comp->ArgumentAt(0)->value(), 618 call->ArgumentAt(0)->value(),
633 String::length_offset(), 619 String::length_offset(),
634 Type::ZoneHandle(Type::SmiType())); 620 Type::ZoneHandle(Type::SmiType()));
635 load->set_result_cid(kSmiCid); 621 load->set_result_cid(kSmiCid);
636 instr->set_computation(load); 622 call->ReplaceWith(load, current_iterator());
637 RemovePushArguments(comp); 623 RemovePushArguments(call);
638 return true; 624 return true;
639 } 625 }
640 return false; 626 return false;
641 } 627 }
642 628
643 629
644 // Inline only simple, frequently called core library methods. 630 // Inline only simple, frequently called core library methods.
645 bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, 631 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
646 InstanceCallComp* comp) { 632 ASSERT(call->HasICData());
647 ASSERT(comp->HasICData()); 633 const ICData& ic_data = *call->ic_data();
648 const ICData& ic_data = *comp->ic_data();
649 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { 634 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) {
650 // No type feedback collected. 635 // No type feedback collected.
651 return false; 636 return false;
652 } 637 }
653 Function& target = Function::Handle(); 638 Function& target = Function::Handle();
654 GrowableArray<intptr_t> class_ids; 639 GrowableArray<intptr_t> class_ids;
655 ic_data.GetCheckAt(0, &class_ids, &target); 640 ic_data.GetCheckAt(0, &class_ids, &target);
656 MethodRecognizer::Kind recognized_kind = 641 MethodRecognizer::Kind recognized_kind =
657 MethodRecognizer::RecognizeKind(target); 642 MethodRecognizer::RecognizeKind(target);
658 643
659 if ((recognized_kind == MethodRecognizer::kDoubleToDouble) && 644 if ((recognized_kind == MethodRecognizer::kDoubleToDouble) &&
660 (class_ids[0] == kDoubleCid)) { 645 (class_ids[0] == kDoubleCid)) {
661 DoubleToDoubleComp* d2d_comp = 646 DoubleToDoubleInstr* d2d_instr =
662 new DoubleToDoubleComp(comp->ArgumentAt(0)->value(), comp); 647 new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), call);
663 instr->set_computation(d2d_comp); 648 call->ReplaceWith(d2d_instr, current_iterator());
664 RemovePushArguments(comp); 649 RemovePushArguments(call);
665 return true; 650 return true;
666 } 651 }
667 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && 652 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) &&
668 (class_ids[0] == kSmiCid)) { 653 (class_ids[0] == kSmiCid)) {
669 SmiToDoubleComp* s2d_comp = new SmiToDoubleComp(comp); 654 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call);
670 instr->set_computation(s2d_comp); 655 call->ReplaceWith(s2d_instr, current_iterator());
671 // Pushed arguments are not removed because SmiToDouble is implemented 656 // Pushed arguments are not removed because SmiToDouble is implemented
672 // as a call. 657 // as a call.
673 return true; 658 return true;
674 } 659 }
675 return false; 660 return false;
676 } 661 }
677 662
678 663
679 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, 664 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
680 BindInstr* instr) { 665 if (instr->HasICData() && (instr->ic_data()->NumberOfChecks() > 0)) {
681 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { 666 const Token::Kind op_kind = instr->token_kind();
682 const Token::Kind op_kind = comp->token_kind();
683 if (Token::IsIndexOperator(op_kind) && 667 if (Token::IsIndexOperator(op_kind) &&
684 TryReplaceWithArrayOp(instr, comp, op_kind)) { 668 TryReplaceWithArrayOp(instr, op_kind)) {
685 return; 669 return;
686 } 670 }
687 if (Token::IsBinaryToken(op_kind) && 671 if (Token::IsBinaryToken(op_kind) &&
688 TryReplaceWithBinaryOp(instr, comp, op_kind)) { 672 TryReplaceWithBinaryOp(instr, op_kind)) {
689 return; 673 return;
690 } 674 }
691 if (Token::IsUnaryToken(op_kind) && 675 if (Token::IsUnaryToken(op_kind) &&
692 TryReplaceWithUnaryOp(instr, comp, op_kind)) { 676 TryReplaceWithUnaryOp(instr, op_kind)) {
693 return; 677 return;
694 } 678 }
695 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr, comp)) { 679 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
696 return; 680 return;
697 } 681 }
698 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { 682 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) {
699 return; 683 return;
700 } 684 }
701 if (TryInlineInstanceMethod(instr, comp)) { 685 if (TryInlineInstanceMethod(instr)) {
702 return; 686 return;
703 } 687 }
704 const intptr_t kMaxChecks = 4; 688 const intptr_t kMaxChecks = 4;
705 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { 689 if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) {
706 const ICData& unary_checks = 690 const ICData& unary_checks =
707 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); 691 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks());
708 bool call_with_checks; 692 bool call_with_checks;
709 // TODO(srdjan): Add check class comp for mixed smi/non-smi. 693 // TODO(srdjan): Add check class instr for mixed smi/non-smi.
710 if (HasOneTarget(unary_checks) && 694 if (HasOneTarget(unary_checks) &&
711 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { 695 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) {
712 // Type propagation has not run yet, we cannot eliminate the check. 696 // Type propagation has not run yet, we cannot eliminate the check.
713 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); 697 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
714 // Call can still deoptimize, do not detach environment from instr. 698 // Call can still deoptimize, do not detach environment from instr.
715 call_with_checks = false; 699 call_with_checks = false;
716 } else { 700 } else {
717 call_with_checks = true; 701 call_with_checks = true;
718 } 702 }
719 PolymorphicInstanceCallComp* call = 703 PolymorphicInstanceCallInstr* call =
720 new PolymorphicInstanceCallComp(comp, 704 new PolymorphicInstanceCallInstr(instr, unary_checks,
721 unary_checks, 705 call_with_checks);
722 call_with_checks); 706 instr->ReplaceWith(call, current_iterator());
723 instr->set_computation(call);
724 } 707 }
725 } 708 }
726 // An instance call without ICData should continue calling via IC calls 709 // An instance call without ICData should continue calling via IC calls
727 // which should trigger reoptimization of optimized code. 710 // which should trigger reoptimization of optimized code.
728 } 711 }
729 712
730 713
731 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp, 714 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* instr) {
732 BindInstr* instr) {
733 MethodRecognizer::Kind recognized_kind = 715 MethodRecognizer::Kind recognized_kind =
734 MethodRecognizer::RecognizeKind(comp->function()); 716 MethodRecognizer::RecognizeKind(instr->function());
735 if (recognized_kind == MethodRecognizer::kMathSqrt) { 717 if (recognized_kind == MethodRecognizer::kMathSqrt) {
736 comp->set_recognized(MethodRecognizer::kMathSqrt); 718 instr->set_recognized(MethodRecognizer::kMathSqrt);
737 } 719 }
738 } 720 }
739 721
740 722
741 bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr, 723 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr) {
742 InstanceCallComp* comp) {
743 if (FLAG_enable_type_checks) { 724 if (FLAG_enable_type_checks) {
744 // TODO(srdjan): Add assignable check node if --enable_type_checks. 725 // TODO(srdjan): Add assignable check node if --enable_type_checks.
745 return false; 726 return false;
746 } 727 }
747 728
748 ASSERT(comp->HasICData()); 729 ASSERT(instr->HasICData());
749 const ICData& ic_data = *comp->ic_data(); 730 const ICData& ic_data = *instr->ic_data();
750 if (ic_data.NumberOfChecks() == 0) { 731 if (ic_data.NumberOfChecks() == 0) {
751 // No type feedback collected. 732 // No type feedback collected.
752 return false; 733 return false;
753 } 734 }
754 if (!HasOneTarget(ic_data)) { 735 if (!HasOneTarget(ic_data)) {
755 // TODO(srdjan): Implement when not all targets are the same. 736 // TODO(srdjan): Implement when not all targets are the same.
756 return false; 737 return false;
757 } 738 }
758 Function& target = Function::Handle(); 739 Function& target = Function::Handle();
759 intptr_t class_id; 740 intptr_t class_id;
760 ic_data.GetOneClassCheckAt(0, &class_id, &target); 741 ic_data.GetOneClassCheckAt(0, &class_id, &target);
761 if (target.kind() != RawFunction::kImplicitSetter) { 742 if (target.kind() != RawFunction::kImplicitSetter) {
762 // Not an implicit setter. 743 // Not an implicit setter.
763 // TODO(srdjan): Inline special setters. 744 // TODO(srdjan): Inline special setters.
764 return false; 745 return false;
765 } 746 }
766 // Inline implicit instance setter. 747 // Inline implicit instance setter.
767 const String& field_name = 748 const String& field_name =
768 String::Handle(Field::NameFromSetter(comp->function_name())); 749 String::Handle(Field::NameFromSetter(instr->function_name()));
769 const Field& field = Field::Handle(GetField(class_id, field_name)); 750 const Field& field = Field::Handle(GetField(class_id, field_name));
770 ASSERT(!field.IsNull()); 751 ASSERT(!field.IsNull());
771 752
772 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); 753 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
773 // Detach environment from the original instruction because it can't 754 // Detach environment from the original instruction because it can't
774 // deoptimize. 755 // deoptimize.
775 instr->set_env(NULL); 756 instr->set_env(NULL);
776 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( 757 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr(
777 field, 758 field,
778 comp->ArgumentAt(0)->value(), 759 instr->ArgumentAt(0)->value(),
779 comp->ArgumentAt(1)->value()); 760 instr->ArgumentAt(1)->value());
780 instr->set_computation(store); 761 instr->ReplaceWith(store, current_iterator());
781 RemovePushArguments(comp); 762 RemovePushArguments(instr);
782 return true; 763 return true;
783 } 764 }
784 765
785 766
786 // TODO(fschneider): Once we get rid of the distinction between Instruction 767 // TODO(fschneider): Once we get rid of the distinction between Instruction
787 // and computation, this helper can go away. 768 // and computation, this helper can go away.
788 static void HandleRelationalOp(FlowGraphOptimizer* optimizer, 769 static void HandleRelationalOp(FlowGraphOptimizer* optimizer,
789 RelationalOpComp* comp, 770 RelationalOpInstr* comp,
790 Instruction* instr) { 771 Instruction* instr) {
791 if (!comp->HasICData()) return; 772 if (!comp->HasICData()) return;
792 773
793 const ICData& ic_data = *comp->ic_data(); 774 const ICData& ic_data = *comp->ic_data();
794 if (ic_data.NumberOfChecks() == 0) return; 775 if (ic_data.NumberOfChecks() == 0) return;
795 // TODO(srdjan): Add multiple receiver type support. 776 // TODO(srdjan): Add multiple receiver type support.
796 if (ic_data.NumberOfChecks() != 1) return; 777 if (ic_data.NumberOfChecks() != 1) return;
797 ASSERT(HasOneTarget(ic_data)); 778 ASSERT(HasOneTarget(ic_data));
798 779
799 if (HasOnlyTwoSmi(ic_data)) { 780 if (HasOnlyTwoSmi(ic_data)) {
800 optimizer->InsertBefore( 781 optimizer->InsertBefore(
801 instr, 782 instr,
802 new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), 783 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
803 instr->env(), 784 instr->env(),
804 Definition::kEffect); 785 Definition::kEffect);
805 optimizer->InsertBefore( 786 optimizer->InsertBefore(
806 instr, 787 instr,
807 new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), 788 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
808 instr->env(), 789 instr->env(),
809 Definition::kEffect); 790 Definition::kEffect);
810 comp->set_operands_class_id(kSmiCid); 791 comp->set_operands_class_id(kSmiCid);
811 } else if (ShouldSpecializeForDouble(ic_data)) { 792 } else if (ShouldSpecializeForDouble(ic_data)) {
812 comp->set_operands_class_id(kDoubleCid); 793 comp->set_operands_class_id(kDoubleCid);
813 } else if (comp->ic_data()->AllReceiversAreNumbers()) { 794 } else if (comp->ic_data()->AllReceiversAreNumbers()) {
814 comp->set_operands_class_id(kNumberCid); 795 comp->set_operands_class_id(kNumberCid);
815 } 796 }
816 } 797 }
817 798
818 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, 799 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) {
819 BindInstr* instr) { 800 HandleRelationalOp(this, instr, instr);
820 HandleRelationalOp(this, comp, instr);
821 } 801 }
822 802
823 803
824 // TODO(fschneider): Once we get rid of the distinction between Instruction 804 // TODO(fschneider): Once we get rid of the distinction between Instruction
825 // and computation, this helper can go away. 805 // and computation, this helper can go away.
826 template <typename T> 806 template <typename T>
827 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, 807 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer,
828 EqualityCompareComp* comp, 808 EqualityCompareInstr* comp,
829 T instr) { 809 T instr,
810 ForwardInstructionIterator* iterator) {
830 // If one of the inputs is null, no ICdata will be collected. 811 // If one of the inputs is null, no ICdata will be collected.
831 if (comp->left()->BindsToConstantNull() || 812 if (comp->left()->BindsToConstantNull() ||
832 comp->right()->BindsToConstantNull()) { 813 comp->right()->BindsToConstantNull()) {
833 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? 814 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ?
834 Token::kEQ_STRICT : Token::kNE_STRICT; 815 Token::kEQ_STRICT : Token::kNE_STRICT;
835 StrictCompareComp* strict_comp = 816 StrictCompareInstr* strict_comp =
836 new StrictCompareComp(strict_kind, comp->left(), comp->right()); 817 new StrictCompareInstr(strict_kind, comp->left(), comp->right());
837 instr->set_computation(strict_comp); 818 instr->ReplaceWith(strict_comp, iterator);
838 return; 819 return;
839 } 820 }
840 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return; 821 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return;
841 if (comp->ic_data()->NumberOfChecks() == 1) { 822 if (comp->ic_data()->NumberOfChecks() == 1) {
842 ASSERT(comp->ic_data()->num_args_tested() == 2); 823 ASSERT(comp->ic_data()->num_args_tested() == 2);
843 GrowableArray<intptr_t> class_ids; 824 GrowableArray<intptr_t> class_ids;
844 Function& target = Function::Handle(); 825 Function& target = Function::Handle();
845 comp->ic_data()->GetCheckAt(0, &class_ids, &target); 826 comp->ic_data()->GetCheckAt(0, &class_ids, &target);
846 // TODO(srdjan): allow for mixed mode comparison. 827 // TODO(srdjan): allow for mixed mode comparison.
847 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { 828 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
848 optimizer->InsertBefore( 829 optimizer->InsertBefore(
849 instr, 830 instr,
850 new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), 831 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
851 instr->env(), 832 instr->env(),
852 Definition::kEffect); 833 Definition::kEffect);
853 optimizer->InsertBefore( 834 optimizer->InsertBefore(
854 instr, 835 instr,
855 new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), 836 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
856 instr->env(), 837 instr->env(),
857 Definition::kEffect); 838 Definition::kEffect);
858 comp->set_receiver_class_id(kSmiCid); 839 comp->set_receiver_class_id(kSmiCid);
859 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { 840 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) {
860 comp->set_receiver_class_id(kDoubleCid); 841 comp->set_receiver_class_id(kDoubleCid);
861 } else { 842 } else {
862 ASSERT(comp->receiver_class_id() == kIllegalCid); 843 ASSERT(comp->receiver_class_id() == kIllegalCid);
863 } 844 }
864 } else if (comp->ic_data()->AllReceiversAreNumbers()) { 845 } else if (comp->ic_data()->AllReceiversAreNumbers()) {
865 comp->set_receiver_class_id(kNumberCid); 846 comp->set_receiver_class_id(kNumberCid);
866 } 847 }
867 } 848 }
868 849
869 850
870 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp, 851 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) {
871 BindInstr* instr) { 852 HandleEqualityCompare(this, instr, instr, current_iterator());
872 HandleEqualityCompare(this, comp, instr);
873 }
874
875
876 void FlowGraphOptimizer::VisitBind(BindInstr* instr) {
877 instr->computation()->Accept(this, instr);
878 } 853 }
879 854
880 855
881 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { 856 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) {
882 ComparisonComp* comparison = instr->computation(); 857 ComparisonInstr* comparison = instr->comparison();
883 if (comparison->IsRelationalOp()) { 858 if (comparison->IsRelationalOp()) {
884 HandleRelationalOp(this, comparison->AsRelationalOp(), instr); 859 HandleRelationalOp(this, comparison->AsRelationalOp(), instr);
885 } else if (comparison->IsEqualityCompare()) { 860 } else if (comparison->IsEqualityCompare()) {
886 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr); 861 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr,
862 current_iterator());
887 } else { 863 } else {
888 ASSERT(comparison->IsStrictCompare()); 864 ASSERT(comparison->IsStrictCompare());
889 // Nothing to do. 865 // Nothing to do.
890 } 866 }
891 } 867 }
892 868
893 869
894 void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, 870 void FlowGraphTypePropagator::VisitBlocks() {
895 BindInstr* instr) { 871 ASSERT(current_iterator_ == NULL);
872 for (intptr_t i = 0; i < block_order_.length(); ++i) {
873 BlockEntryInstr* entry = block_order_[i];
874 entry->Accept(this);
875 ForwardInstructionIterator it(entry);
876 current_iterator_ = &it;
877 for (; !it.Done(); it.Advance()) {
878 Instruction* current = it.Current();
879 // No need to propagate the input types of the instruction, as long as
880 // PhiInstr's are handled as part of JoinEntryInstr.
881
882 // Visit the instruction and possibly eliminate type checks.
883 current->Accept(this);
884 // The instruction may have been removed from the graph.
885 Definition* defn = current->AsDefinition();
886 if ((defn != NULL) &&
887 !defn->IsPushArgument() &&
Kevin Millikin (Google) 2012/09/05 12:50:09 This line is added.
888 (defn->previous() != NULL)) {
889 // Cache the propagated computation type.
890 AbstractType& type = AbstractType::Handle(defn->CompileType());
891 still_changing_ = defn->SetPropagatedType(type) || still_changing_;
892
893 // Propagate class ids.
894 const intptr_t cid = defn->ResultCid();
895 still_changing_ = defn->SetPropagatedCid(cid) || still_changing_;
896 }
897 }
898 current_iterator_ = NULL;
899 }
900 }
901
902
903 void FlowGraphTypePropagator::VisitAssertAssignable(
904 AssertAssignableInstr* instr) {
896 if (FLAG_eliminate_type_checks && 905 if (FLAG_eliminate_type_checks &&
897 !comp->is_eliminated() && 906 !instr->is_eliminated() &&
898 comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { 907 instr->value()->CompileTypeIsMoreSpecificThan(instr->dst_type())) {
899 // TODO(regis): Remove is_eliminated_ field and support. 908 // TODO(regis): Remove is_eliminated_ field and support.
900 comp->eliminate(); 909 instr->eliminate();
901 910
902 Value* use = comp->value(); 911 Value* use = instr->value();
903 ASSERT(use != NULL); 912 ASSERT(use != NULL);
904 Definition* result = use->definition(); 913 Definition* result = use->definition();
905 ASSERT(result != NULL); 914 ASSERT(result != NULL);
906 // Replace uses and remove the current instructions via the iterator. 915 // Replace uses and remove the current instruction via the iterator.
907 instr->ReplaceUsesWith(result); 916 instr->ReplaceUsesWith(result);
908 ASSERT(current_iterator()->Current() == instr); 917 ASSERT(current_iterator()->Current() == instr);
909 current_iterator()->RemoveCurrentFromGraph(); 918 current_iterator()->RemoveCurrentFromGraph();
910 if (FLAG_trace_optimization) { 919 if (FLAG_trace_optimization) {
911 OS::Print("Replacing v%d with v%d\n", 920 OS::Print("Replacing v%d with v%d\n",
912 instr->ssa_temp_index(), 921 instr->ssa_temp_index(),
913 result->ssa_temp_index()); 922 result->ssa_temp_index());
914 } 923 }
915 924
916 if (FLAG_trace_type_check_elimination) { 925 if (FLAG_trace_type_check_elimination) {
917 FlowGraphPrinter::PrintTypeCheck(parsed_function(), 926 FlowGraphPrinter::PrintTypeCheck(parsed_function(),
918 comp->token_pos(), 927 instr->token_pos(),
919 comp->value(), 928 instr->value(),
920 comp->dst_type(), 929 instr->dst_type(),
921 comp->dst_name(), 930 instr->dst_name(),
922 comp->is_eliminated()); 931 instr->is_eliminated());
923 } 932 }
924 } 933 }
925 } 934 }
926 935
927 936
928 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, 937 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanInstr* instr) {
929 BindInstr* instr) {
930 // TODO(regis): Propagate NullType as well and revise the comment and code 938 // TODO(regis): Propagate NullType as well and revise the comment and code
931 // below to also eliminate the test for non-null and non-constant value. 939 // below to also eliminate the test for non-null and non-constant value.
932 940
933 // We can only eliminate an 'assert boolean' test when the checked value is 941 // We can only eliminate an 'assert boolean' test when the checked value is
934 // a constant time constant. Indeed, a variable of the proper compile time 942 // a constant time constant. Indeed, a variable of the proper compile time
935 // type (bool) may still hold null at run time and therefore fail the test. 943 // type (bool) may still hold null at run time and therefore fail the test.
936 if (FLAG_eliminate_type_checks && 944 if (FLAG_eliminate_type_checks &&
937 !comp->is_eliminated() && 945 !instr->is_eliminated() &&
938 comp->value()->BindsToConstant() && 946 instr->value()->BindsToConstant() &&
939 !comp->value()->BindsToConstantNull() && 947 !instr->value()->BindsToConstantNull() &&
940 comp->value()->CompileTypeIsMoreSpecificThan( 948 instr->value()->CompileTypeIsMoreSpecificThan(
941 Type::Handle(Type::BoolType()))) { 949 Type::Handle(Type::BoolType()))) {
942 // TODO(regis): Remove is_eliminated_ field and support. 950 // TODO(regis): Remove is_eliminated_ field and support.
943 comp->eliminate(); 951 instr->eliminate();
944 952
945 Value* use = comp->value(); 953 Value* use = instr->value();
946 Definition* result = use->definition(); 954 Definition* result = use->definition();
947 ASSERT(result != NULL); 955 ASSERT(result != NULL);
948 // Replace uses and remove the current instructions via the iterator. 956 // Replace uses and remove the current instruction via the iterator.
949 instr->ReplaceUsesWith(result); 957 instr->ReplaceUsesWith(result);
950 ASSERT(current_iterator()->Current() == instr); 958 ASSERT(current_iterator()->Current() == instr);
951 current_iterator()->RemoveCurrentFromGraph(); 959 current_iterator()->RemoveCurrentFromGraph();
952 if (FLAG_trace_optimization) { 960 if (FLAG_trace_optimization) {
953 OS::Print("Replacing v%d with v%d\n", 961 OS::Print("Replacing v%d with v%d\n",
954 instr->ssa_temp_index(), 962 instr->ssa_temp_index(),
955 result->ssa_temp_index()); 963 result->ssa_temp_index());
956 } 964 }
957 965
958 if (FLAG_trace_type_check_elimination) { 966 if (FLAG_trace_type_check_elimination) {
959 const String& name = String::Handle(Symbols::New("boolean expression")); 967 const String& name = String::Handle(Symbols::New("boolean expression"));
960 FlowGraphPrinter::PrintTypeCheck(parsed_function(), 968 FlowGraphPrinter::PrintTypeCheck(parsed_function(),
961 comp->token_pos(), 969 instr->token_pos(),
962 comp->value(), 970 instr->value(),
963 Type::Handle(Type::BoolType()), 971 Type::Handle(Type::BoolType()),
964 name, 972 name,
965 comp->is_eliminated()); 973 instr->is_eliminated());
966 } 974 }
967 } 975 }
968 } 976 }
969 977
970 978
971 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfComp* comp, 979 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) {
972 BindInstr* instr) {
973 // TODO(regis): Propagate NullType as well and revise the comment and code 980 // TODO(regis): Propagate NullType as well and revise the comment and code
974 // below to also eliminate the test for non-null and non-constant value. 981 // below to also eliminate the test for non-null and non-constant value.
975 982
976 // We can only eliminate an 'instance of' test when the checked value is 983 // We can only eliminate an 'instance of' test when the checked value is
977 // a constant time constant. Indeed, a variable of the proper compile time 984 // a constant time constant. Indeed, a variable of the proper compile time
978 // type may still hold null at run time and therefore fail the test. 985 // type may still hold null at run time and therefore fail the test.
979 // We do not bother checking for Object destination type, since the graph 986 // We do not bother checking for Object destination type, since the graph
980 // builder did already. 987 // builder did already.
981 if (FLAG_eliminate_type_checks && 988 if (FLAG_eliminate_type_checks &&
982 comp->value()->BindsToConstant() && 989 instr->value()->BindsToConstant() &&
983 !comp->value()->BindsToConstantNull() && 990 !instr->value()->BindsToConstantNull() &&
984 comp->value()->CompileTypeIsMoreSpecificThan(comp->type())) { 991 instr->value()->CompileTypeIsMoreSpecificThan(instr->type())) {
985 Value* use = comp->value(); 992 Value* use = instr->value();
986 Definition* result = use->definition(); 993 Definition* result = use->definition();
987 ASSERT(result != NULL); 994 ASSERT(result != NULL);
988 // Replace uses and remove the current instructions via the iterator. 995 // Replace uses and remove the current instruction via the iterator.
989 instr->ReplaceUsesWith(result); 996 instr->ReplaceUsesWith(result);
990 ASSERT(current_iterator()->Current() == instr); 997 ASSERT(current_iterator()->Current() == instr);
991 current_iterator()->RemoveCurrentFromGraph(); 998 current_iterator()->RemoveCurrentFromGraph();
992 if (FLAG_trace_optimization) { 999 if (FLAG_trace_optimization) {
993 OS::Print("Replacing v%d with v%d\n", 1000 OS::Print("Replacing v%d with v%d\n",
994 instr->ssa_temp_index(), 1001 instr->ssa_temp_index(),
995 result->ssa_temp_index()); 1002 result->ssa_temp_index());
996 } 1003 }
997 1004
998 if (FLAG_trace_type_check_elimination) { 1005 if (FLAG_trace_type_check_elimination) {
999 const String& name = String::Handle(Symbols::New("InstanceOf")); 1006 const String& name = String::Handle(Symbols::New("InstanceOf"));
1000 FlowGraphPrinter::PrintTypeCheck(parsed_function(), 1007 FlowGraphPrinter::PrintTypeCheck(parsed_function(),
1001 comp->token_pos(), 1008 instr->token_pos(),
1002 comp->value(), 1009 instr->value(),
1003 comp->type(), 1010 instr->type(),
1004 name, 1011 name,
1005 /* eliminated = */ true); 1012 /* eliminated = */ true);
1006 } 1013 }
1007 } 1014 }
1008 } 1015 }
1009 1016
1010 1017
1011 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) { 1018 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) {
1012 if (graph_entry->start_env() == NULL) { 1019 if (graph_entry->start_env() == NULL) {
1013 return; 1020 return;
(...skipping 21 matching lines...) Expand all
1035 } 1042 }
1036 } 1043 }
1037 1044
1038 1045
1039 // TODO(srdjan): Investigate if the propagated cid should be more specific. 1046 // TODO(srdjan): Investigate if the propagated cid should be more specific.
1040 void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) { 1047 void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) {
1041 if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid); 1048 if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid);
1042 } 1049 }
1043 1050
1044 1051
1045 void FlowGraphTypePropagator::VisitBind(BindInstr* bind) {
1046 // No need to propagate the input types of the bound computation, as long as
1047 // PhiInstr's are handled as part of JoinEntryInstr.
1048 // Visit computation and possibly eliminate type check.
1049 bind->computation()->Accept(this, bind);
1050 // The current bind may have been removed from the graph.
1051 if (current_iterator()->Current() == bind) {
1052 // Current bind was not removed.
1053 // Cache propagated computation type.
1054 AbstractType& computation_type =
1055 AbstractType::Handle(bind->computation()->CompileType());
1056 bool changed = bind->SetPropagatedType(computation_type);
1057 if (changed) {
1058 still_changing_ = true;
1059 }
1060 // Propagate class ids.
1061 const intptr_t cid = bind->computation()->ResultCid();
1062 changed = bind->SetPropagatedCid(cid);
1063 if (changed) {
1064 still_changing_ = true;
1065 }
1066 }
1067 }
1068
1069
1070 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { 1052 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) {
1071 // We could set the propagated type of the phi to the least upper bound of its 1053 // We could set the propagated type of the phi to the least upper bound of its
1072 // input propagated types. However, keeping all propagated types allows us to 1054 // input propagated types. However, keeping all propagated types allows us to
1073 // optimize method dispatch. 1055 // optimize method dispatch.
1074 // TODO(regis): Support a set of propagated types. For now, we compute the 1056 // TODO(regis): Support a set of propagated types. For now, we compute the
1075 // least specific of the input propagated types. 1057 // least specific of the input propagated types.
1076 AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType()); 1058 AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType());
1077 bool changed = phi->SetPropagatedType(type); 1059 bool changed = phi->SetPropagatedType(type);
1078 if (changed) { 1060 if (changed) {
1079 still_changing_ = true; 1061 still_changing_ = true;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1158 is_leaf_ = false; 1140 is_leaf_ = false;
1159 return; 1141 return;
1160 } 1142 }
1161 } 1143 }
1162 } 1144 }
1163 } 1145 }
1164 1146
1165 1147
1166 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { 1148 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) {
1167 ASSERT(graph_entry->IsGraphEntry()); 1149 ASSERT(graph_entry->IsGraphEntry());
1168 DirectChainedHashMap<BindInstr*> map; 1150 DirectChainedHashMap<Definition*> map;
1169 OptimizeRecursive(graph_entry, &map); 1151 OptimizeRecursive(graph_entry, &map);
1170 } 1152 }
1171 1153
1172 1154
1173 void DominatorBasedCSE::OptimizeRecursive( 1155 void DominatorBasedCSE::OptimizeRecursive(
1174 BlockEntryInstr* block, 1156 BlockEntryInstr* block,
1175 DirectChainedHashMap<BindInstr*>* map) { 1157 DirectChainedHashMap<Definition*>* map) {
1176 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { 1158 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
1177 BindInstr* instr = it.Current()->AsBind(); 1159 Definition* defn = it.Current()->AsDefinition();
1178 if (instr == NULL || instr->computation()->HasSideEffect()) continue; 1160 if ((defn == NULL) || defn->HasSideEffect()) continue;
1179 BindInstr* result = map->Lookup(instr); 1161 Definition* result = map->Lookup(defn);
1180 if (result == NULL) { 1162 if (result == NULL) {
1181 map->Insert(instr); 1163 map->Insert(defn);
1182 continue; 1164 continue;
1183 } 1165 }
1184 // Replace current with lookup result. 1166 // Replace current with lookup result.
1185 instr->ReplaceUsesWith(result); 1167 defn->ReplaceUsesWith(result);
1186 it.RemoveCurrentFromGraph(); 1168 it.RemoveCurrentFromGraph();
1187 if (FLAG_trace_optimization) { 1169 if (FLAG_trace_optimization) {
1188 OS::Print("Replacing v%d with v%d\n", 1170 OS::Print("Replacing v%d with v%d\n",
1189 instr->ssa_temp_index(), 1171 defn->ssa_temp_index(),
1190 result->ssa_temp_index()); 1172 result->ssa_temp_index());
1191 } 1173 }
1192 } 1174 }
1193 1175
1194 // Process children in the dominator tree recursively. 1176 // Process children in the dominator tree recursively.
1195 intptr_t num_children = block->dominated_blocks().length(); 1177 intptr_t num_children = block->dominated_blocks().length();
1196 for (intptr_t i = 0; i < num_children; ++i) { 1178 for (intptr_t i = 0; i < num_children; ++i) {
1197 BlockEntryInstr* child = block->dominated_blocks()[i]; 1179 BlockEntryInstr* child = block->dominated_blocks()[i];
1198 if (i < num_children - 1) { 1180 if (i < num_children - 1) {
1199 DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. 1181 DirectChainedHashMap<Definition*> child_map(*map); // Copy map.
1200 OptimizeRecursive(child, &child_map); 1182 OptimizeRecursive(child, &child_map);
1201 } else { 1183 } else {
1202 OptimizeRecursive(child, map); // Reuse map for the last child. 1184 OptimizeRecursive(child, map); // Reuse map for the last child.
1203 } 1185 }
1204 } 1186 }
1205 } 1187 }
1206 1188
1207 1189
1208 } // namespace dart 1190 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/il_printer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698