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

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

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