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

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

Issue 263243002: Enables many language tests for arm64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 7 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_compiler_x64.cc ('k') | runtime/vm/simulator_arm64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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/globals.h" // Needed here to get TARGET_ARCH_ARM64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64.
6 #if defined(TARGET_ARCH_ARM64) 6 #if defined(TARGET_ARCH_ARM64)
7 7
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 __ CompareImmediate(R2, fp_sp_dist, PP); 90 __ CompareImmediate(R2, fp_sp_dist, PP);
91 __ b(&stack_ok, EQ); 91 __ b(&stack_ok, EQ);
92 __ hlt(0); 92 __ hlt(0);
93 __ Bind(&stack_ok); 93 __ Bind(&stack_ok);
94 #endif 94 #endif
95 __ LeaveDartFrame(); 95 __ LeaveDartFrame();
96 __ ret(); 96 __ ret();
97 } 97 }
98 98
99 99
100 static Condition NegateCondition(Condition condition) {
101 switch (condition) {
102 case EQ: return NE;
103 case NE: return EQ;
104 case LT: return GE;
105 case LE: return GT;
106 case GT: return LE;
107 case GE: return LT;
108 case CC: return CS;
109 case LS: return HI;
110 case HI: return LS;
111 case CS: return CC;
112 default:
113 UNREACHABLE();
114 return EQ;
115 }
116 }
117
118
119 // Detect pattern when one value is zero and another is a power of 2.
120 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) {
121 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) ||
122 (Utils::IsPowerOfTwo(v2) && (v1 == 0));
123 }
124
125
100 LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const { 126 LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const {
101 UNIMPLEMENTED(); 127 comparison()->InitializeLocationSummary(opt);
102 return NULL; 128 return comparison()->locs();
103 } 129 }
104 130
105 131
106 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 132 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
107 UNIMPLEMENTED(); 133 const Register result = locs()->out(0).reg();
134
135 Location left = locs()->in(0);
136 Location right = locs()->in(1);
137 ASSERT(!left.IsConstant() || !right.IsConstant());
138
139 // Emit comparison code. This must not overwrite the result register.
140 BranchLabels labels = { NULL, NULL, NULL };
141 Condition true_condition = comparison()->EmitComparisonCode(compiler, labels);
142
143 const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_);
144
145 intptr_t true_value = if_true_;
146 intptr_t false_value = if_false_;
147
148 if (is_power_of_two_kind) {
149 if (true_value == 0) {
150 // We need to have zero in result on true_condition.
151 true_condition = NegateCondition(true_condition);
152 }
153 } else {
154 if (true_value == 0) {
155 // Swap values so that false_value is zero.
156 intptr_t temp = true_value;
157 true_value = false_value;
158 false_value = temp;
159 } else {
160 true_condition = NegateCondition(true_condition);
161 }
162 }
163
164 // TODO(zra): replace with cinc(result, ZR, ZR, true_condition)
165 __ LoadImmediate(TMP, 1, kNoPP);
166 __ csel(result, TMP, ZR, true_condition);
167
168 if (is_power_of_two_kind) {
169 const intptr_t shift =
170 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value));
171 __ Lsl(result, result, shift + kSmiTagSize);
172 } else {
173 __ sub(result, result, Operand(1));
174 const int32_t val =
175 Smi::RawValue(true_value) - Smi::RawValue(false_value);
176 __ AndImmediate(result, result, val, PP);
177 if (false_value != 0) {
178 __ AddImmediate(result, result, Smi::RawValue(false_value), PP);
179 }
180 }
108 } 181 }
109 182
110 183
111 LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const { 184 LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const {
112 const intptr_t kNumInputs = 1; 185 const intptr_t kNumInputs = 1;
113 const intptr_t kNumTemps = 0; 186 const intptr_t kNumTemps = 0;
114 LocationSummary* summary = 187 LocationSummary* summary =
115 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); 188 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
116 summary->set_in(0, Location::RegisterLocation(R0)); // Function. 189 summary->set_in(0, Location::RegisterLocation(R0)); // Function.
117 summary->set_out(0, Location::RegisterLocation(R0)); 190 summary->set_out(0, Location::RegisterLocation(R0));
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 340
268 void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 341 void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
269 Register obj = locs()->in(0).reg(); 342 Register obj = locs()->in(0).reg();
270 Register result = locs()->out(0).reg(); 343 Register result = locs()->out(0).reg();
271 344
272 EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler); 345 EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
273 ASSERT(obj == result); 346 ASSERT(obj == result);
274 } 347 }
275 348
276 349
350 static Condition TokenKindToSmiCondition(Token::Kind kind) {
351 switch (kind) {
352 case Token::kEQ: return EQ;
353 case Token::kNE: return NE;
354 case Token::kLT: return LT;
355 case Token::kGT: return GT;
356 case Token::kLTE: return LE;
357 case Token::kGTE: return GE;
358 default:
359 UNREACHABLE();
360 return VS;
361 }
362 }
363
364
365 static Condition FlipCondition(Condition condition) {
366 switch (condition) {
367 case EQ: return EQ;
368 case NE: return NE;
369 case LT: return GT;
370 case LE: return GE;
371 case GT: return LT;
372 case GE: return LE;
373 case CC: return HI;
374 case LS: return CS;
375 case HI: return CC;
376 case CS: return LS;
377 default:
378 UNREACHABLE();
379 return EQ;
380 }
381 }
382
383
384 static void EmitBranchOnCondition(FlowGraphCompiler* compiler,
385 Condition true_condition,
386 BranchLabels labels) {
387 if (labels.fall_through == labels.false_label) {
388 // If the next block is the false successor we will fall through to it.
389 __ b(labels.true_label, true_condition);
390 } else {
391 // If the next block is not the false successor we will branch to it.
392 Condition false_condition = NegateCondition(true_condition);
393 __ b(labels.false_label, false_condition);
394
395 // Fall through or jump to the true successor.
396 if (labels.fall_through != labels.true_label) {
397 __ b(labels.true_label);
398 }
399 }
400 }
401
402
403 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler,
404 LocationSummary* locs,
405 Token::Kind kind) {
406 Location left = locs->in(0);
407 Location right = locs->in(1);
408 ASSERT(!left.IsConstant() || !right.IsConstant());
409
410 Condition true_condition = TokenKindToSmiCondition(kind);
411
412 if (left.IsConstant()) {
413 __ CompareObject(right.reg(), left.constant(), PP);
414 true_condition = FlipCondition(true_condition);
415 } else if (right.IsConstant()) {
416 __ CompareObject(left.reg(), right.constant(), PP);
417 } else {
418 __ CompareRegisters(left.reg(), right.reg());
419 }
420 return true_condition;
421 }
422
423
277 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const { 424 LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const {
278 UNIMPLEMENTED(); 425 const intptr_t kNumInputs = 2;
426 if (operation_cid() == kDoubleCid) {
427 const intptr_t kNumTemps = 0;
428 LocationSummary* locs =
429 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
430 locs->set_in(0, Location::RequiresFpuRegister());
431 locs->set_in(1, Location::RequiresFpuRegister());
432 locs->set_out(0, Location::RequiresRegister());
433 return locs;
434 }
435 if (operation_cid() == kSmiCid) {
436 const intptr_t kNumTemps = 0;
437 LocationSummary* locs =
438 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
439 locs->set_in(0, Location::RegisterOrConstant(left()));
440 // Only one input can be a constant operand. The case of two constant
441 // operands should be handled by constant propagation.
442 // Only right can be a stack slot.
443 locs->set_in(1, locs->in(0).IsConstant()
444 ? Location::RequiresRegister()
445 : Location::RegisterOrConstant(right()));
446 locs->set_out(0, Location::RequiresRegister());
447 return locs;
448 }
449 UNREACHABLE();
279 return NULL; 450 return NULL;
280 } 451 }
281 452
282 453
283 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, 454 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
284 BranchLabels labels) { 455 BranchLabels labels) {
285 UNIMPLEMENTED(); 456 if (operation_cid() == kSmiCid) {
286 return VS; 457 return EmitSmiComparisonOp(compiler, locs(), kind());
458 } else {
459 UNIMPLEMENTED();
460 return VS;
461 }
287 } 462 }
288 463
289 464
290 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 465 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
291 UNIMPLEMENTED(); 466 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE));
467
468 Label is_true, is_false;
469 BranchLabels labels = { &is_true, &is_false, &is_false };
470 Condition true_condition = EmitComparisonCode(compiler, labels);
471 EmitBranchOnCondition(compiler, true_condition, labels);
472
473 // TODO(zra): instead of branching, use the csel instruction to get
474 // True or False into result.
475 Register result = locs()->out(0).reg();
476 Label done;
477 __ Bind(&is_false);
478 __ LoadObject(result, Bool::False(), PP);
479 __ b(&done);
480 __ Bind(&is_true);
481 __ LoadObject(result, Bool::True(), PP);
482 __ Bind(&done);
292 } 483 }
293 484
294 485
295 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, 486 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
296 BranchInstr* branch) { 487 BranchInstr* branch) {
297 UNIMPLEMENTED(); 488 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
489
490 BranchLabels labels = compiler->CreateBranchLabels(branch);
491 Condition true_condition = EmitComparisonCode(compiler, labels);
492 EmitBranchOnCondition(compiler, true_condition, labels);
298 } 493 }
299 494
300 495
301 LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const { 496 LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const {
302 UNIMPLEMENTED(); 497 const intptr_t kNumInputs = 2;
303 return NULL; 498 const intptr_t kNumTemps = 0;
499 LocationSummary* locs =
500 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
501 locs->set_in(0, Location::RequiresRegister());
502 // Only one input can be a constant operand. The case of two constant
503 // operands should be handled by constant propagation.
504 locs->set_in(1, Location::RegisterOrConstant(right()));
505 return locs;
304 } 506 }
305 507
306 508
307 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, 509 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
308 BranchLabels labels) { 510 BranchLabels labels) {
309 UNIMPLEMENTED(); 511 Register left = locs()->in(0).reg();
310 return VS; 512 Location right = locs()->in(1);
513 if (right.IsConstant()) {
514 ASSERT(right.constant().IsSmi());
515 const int32_t imm =
516 reinterpret_cast<int64_t>(right.constant().raw());
517 __ TestImmediate(left, imm, PP);
518 } else {
519 __ tst(left, Operand(right.reg()));
520 }
521 Condition true_condition = (kind() == Token::kNE) ? NE : EQ;
522 return true_condition;
311 } 523 }
312 524
525
313 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 526 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
314 UNIMPLEMENTED(); 527 // Never emitted outside of the BranchInstr.
528 UNREACHABLE();
315 } 529 }
316 530
317 531
318 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, 532 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler,
319 BranchInstr* branch) { 533 BranchInstr* branch) {
320 UNIMPLEMENTED(); 534 BranchLabels labels = compiler->CreateBranchLabels(branch);
535 Condition true_condition = EmitComparisonCode(compiler, labels);
536 EmitBranchOnCondition(compiler, true_condition, labels);
321 } 537 }
322 538
323 539
324 LocationSummary* TestCidsInstr::MakeLocationSummary(bool opt) const { 540 LocationSummary* TestCidsInstr::MakeLocationSummary(bool opt) const {
325 const intptr_t kNumInputs = 1; 541 const intptr_t kNumInputs = 1;
326 const intptr_t kNumTemps = 1; 542 const intptr_t kNumTemps = 1;
327 LocationSummary* locs = 543 LocationSummary* locs =
328 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 544 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
329 locs->set_in(0, Location::RequiresRegister()); 545 locs->set_in(0, Location::RequiresRegister());
330 locs->set_temp(0, Location::RequiresRegister()); 546 locs->set_temp(0, Location::RequiresRegister());
331 locs->set_out(0, Location::RequiresRegister()); 547 locs->set_out(0, Location::RequiresRegister());
332 return locs; 548 return locs;
333 } 549 }
334 550
335 551
336 Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler, 552 Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
337 BranchLabels labels) { 553 BranchLabels labels) {
338 UNIMPLEMENTED(); 554 ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT));
555 Register val_reg = locs()->in(0).reg();
556 Register cid_reg = locs()->temp(0).reg();
557
558 Label* deopt = CanDeoptimize() ?
559 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL;
560
561 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
562 const ZoneGrowableArray<intptr_t>& data = cid_results();
563 ASSERT(data[0] == kSmiCid);
564 bool result = data[1] == true_result;
565 __ tsti(val_reg, kSmiTagMask);
566 __ b(result ? labels.true_label : labels.false_label, EQ);
567 __ LoadClassId(cid_reg, val_reg);
568
569 for (intptr_t i = 2; i < data.length(); i += 2) {
570 const intptr_t test_cid = data[i];
571 ASSERT(test_cid != kSmiCid);
572 result = data[i + 1] == true_result;
573 __ CompareImmediate(cid_reg, test_cid, PP);
574 __ b(result ? labels.true_label : labels.false_label, EQ);
575 }
576 // No match found, deoptimize or false.
577 if (deopt == NULL) {
578 Label* target = result ? labels.false_label : labels.true_label;
579 if (target != labels.fall_through) {
580 __ b(target);
581 }
582 } else {
583 __ b(deopt);
584 }
585 // Dummy result as the last instruction is a jump, any conditional
586 // branch using the result will therefore be skipped.
339 return EQ; 587 return EQ;
340 } 588 }
341 589
342 590
343 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, 591 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler,
344 BranchInstr* branch) { 592 BranchInstr* branch) {
345 UNIMPLEMENTED(); 593 BranchLabels labels = compiler->CreateBranchLabels(branch);
594 EmitComparisonCode(compiler, labels);
346 } 595 }
347 596
348 597
349 void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 598 void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
350 UNIMPLEMENTED(); 599 Register result_reg = locs()->out(0).reg();
600 Label is_true, is_false, done;
601 BranchLabels labels = { &is_true, &is_false, &is_false };
602 EmitComparisonCode(compiler, labels);
603 // TODO(zra): instead of branching, use the csel instruction to get
604 // True or False into result.
605 __ Bind(&is_false);
606 __ LoadObject(result_reg, Bool::False(), PP);
607 __ b(&done);
608 __ Bind(&is_true);
609 __ LoadObject(result_reg, Bool::True(), PP);
610 __ Bind(&done);
351 } 611 }
352 612
353 613
354 LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const { 614 LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const {
355 UNIMPLEMENTED(); 615 const intptr_t kNumInputs = 2;
356 return NULL; 616 const intptr_t kNumTemps = 0;
617 if (operation_cid() == kDoubleCid) {
618 LocationSummary* summary =
619 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
620 summary->set_in(0, Location::RequiresFpuRegister());
621 summary->set_in(1, Location::RequiresFpuRegister());
622 summary->set_out(0, Location::RequiresRegister());
623 return summary;
624 }
625 ASSERT(operation_cid() == kSmiCid);
626 LocationSummary* summary =
627 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
628 summary->set_in(0, Location::RegisterOrConstant(left()));
629 // Only one input can be a constant operand. The case of two constant
630 // operands should be handled by constant propagation.
631 summary->set_in(1, summary->in(0).IsConstant()
632 ? Location::RequiresRegister()
633 : Location::RegisterOrConstant(right()));
634 summary->set_out(0, Location::RequiresRegister());
635 return summary;
357 } 636 }
358 637
359 638
360 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, 639 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
361 BranchLabels labels) { 640 BranchLabels labels) {
362 UNIMPLEMENTED(); 641 if (operation_cid() == kSmiCid) {
363 return VS; 642 return EmitSmiComparisonOp(compiler, locs(), kind());
643 } else {
644 UNIMPLEMENTED();
645 return VS;
646 }
364 } 647 }
365 648
366 649
367 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 650 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
368 UNIMPLEMENTED(); 651 Label is_true, is_false;
652 BranchLabels labels = { &is_true, &is_false, &is_false };
653 Condition true_condition = EmitComparisonCode(compiler, labels);
654 EmitBranchOnCondition(compiler, true_condition, labels);
655 // TODO(zra): instead of branching, use the csel instruction to get
656 // True or False into result.
657 Register result = locs()->out(0).reg();
658 Label done;
659 __ Bind(&is_false);
660 __ LoadObject(result, Bool::False(), PP);
661 __ b(&done);
662 __ Bind(&is_true);
663 __ LoadObject(result, Bool::True(), PP);
664 __ Bind(&done);
369 } 665 }
370 666
371 667
372 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, 668 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
373 BranchInstr* branch) { 669 BranchInstr* branch) {
374 UNIMPLEMENTED(); 670 BranchLabels labels = compiler->CreateBranchLabels(branch);
671 Condition true_condition = EmitComparisonCode(compiler, labels);
672 EmitBranchOnCondition(compiler, true_condition, labels);
375 } 673 }
376 674
377 675
378 LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const { 676 LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const {
379 const intptr_t kNumInputs = 0; 677 const intptr_t kNumInputs = 0;
380 const intptr_t kNumTemps = 3; 678 const intptr_t kNumTemps = 3;
381 LocationSummary* locs = 679 LocationSummary* locs =
382 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); 680 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
383 locs->set_temp(0, Location::RegisterLocation(R1)); 681 locs->set_temp(0, Location::RegisterLocation(R1));
384 locs->set_temp(1, Location::RegisterLocation(R2)); 682 locs->set_temp(1, Location::RegisterLocation(R2));
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 __ LoadImmediate(R1, NativeArguments::ComputeArgcTag(function()), PP); 728 __ LoadImmediate(R1, NativeArguments::ComputeArgcTag(function()), PP);
431 compiler->GenerateCall(token_pos(), 729 compiler->GenerateCall(token_pos(),
432 stub_entry, 730 stub_entry,
433 PcDescriptors::kOther, 731 PcDescriptors::kOther,
434 locs()); 732 locs());
435 __ Pop(result); 733 __ Pop(result);
436 } 734 }
437 735
438 736
439 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const { 737 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const {
440 UNIMPLEMENTED(); 738 const intptr_t kNumInputs = 1;
441 return NULL; 739 // TODO(fschneider): Allow immediate operands for the char code.
740 return LocationSummary::Make(kNumInputs,
741 Location::RequiresRegister(),
742 LocationSummary::kNoCall);
442 } 743 }
443 744
444 745
445 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 746 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
446 UNIMPLEMENTED(); 747 Register char_code = locs()->in(0).reg();
748 Register result = locs()->out(0).reg();
749 __ LoadImmediate(result,
750 reinterpret_cast<uword>(Symbols::PredefinedAddress()), PP);
751 __ AddImmediate(
752 result, result, Symbols::kNullCharCodeSymbolOffset * kWordSize, PP);
753 __ Asr(TMP, char_code, kSmiTagShift); // Untag to use scaled adress mode.
754 __ ldr(result, Address(result, TMP, UXTX, Address::Scaled));
447 } 755 }
448 756
449 757
450 LocationSummary* StringToCharCodeInstr::MakeLocationSummary(bool opt) const { 758 LocationSummary* StringToCharCodeInstr::MakeLocationSummary(bool opt) const {
451 UNIMPLEMENTED(); 759 const intptr_t kNumInputs = 1;
452 return NULL; 760 return LocationSummary::Make(kNumInputs,
761 Location::RequiresRegister(),
762 LocationSummary::kNoCall);
453 } 763 }
454 764
455 765
456 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 766 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
457 UNIMPLEMENTED(); 767 ASSERT(cid_ == kOneByteStringCid);
768 Register str = locs()->in(0).reg();
769 Register result = locs()->out(0).reg();
770 __ LoadFieldFromOffset(result, str, String::length_offset());
771 __ CompareImmediate(result, Smi::RawValue(1), PP);
772 __ LoadImmediate(TMP, Smi::RawValue(-1), PP);
773 __ ldr(TMP2, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte);
774 __ csel(result, TMP, result, NE);
775 __ csel(result, TMP2, result, EQ);
776 __ SmiTag(result);
458 } 777 }
459 778
460 779
461 LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const { 780 LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const {
462 const intptr_t kNumInputs = 1; 781 const intptr_t kNumInputs = 1;
463 const intptr_t kNumTemps = 0; 782 const intptr_t kNumTemps = 0;
464 LocationSummary* summary = 783 LocationSummary* summary =
465 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); 784 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
466 summary->set_in(0, Location::RegisterLocation(R0)); 785 summary->set_in(0, Location::RegisterLocation(R0));
467 summary->set_out(0, Location::RegisterLocation(R0)); 786 summary->set_out(0, Location::RegisterLocation(R0));
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP); 831 __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP);
513 __ b(&done); 832 __ b(&done);
514 __ Bind(&load); 833 __ Bind(&load);
515 __ LoadClassId(result, object); 834 __ LoadClassId(result, object);
516 __ SmiTag(result); 835 __ SmiTag(result);
517 __ Bind(&done); 836 __ Bind(&done);
518 } 837 }
519 838
520 839
521 CompileType LoadIndexedInstr::ComputeType() const { 840 CompileType LoadIndexedInstr::ComputeType() const {
522 UNIMPLEMENTED(); 841 switch (class_id_) {
523 return CompileType::Dynamic(); 842 case kArrayCid:
843 case kImmutableArrayCid:
844 return CompileType::Dynamic();
845
846 case kTypedDataFloat32ArrayCid:
847 case kTypedDataFloat64ArrayCid:
848 return CompileType::FromCid(kDoubleCid);
849 case kTypedDataFloat32x4ArrayCid:
850 return CompileType::FromCid(kFloat32x4Cid);
851 case kTypedDataInt32x4ArrayCid:
852 return CompileType::FromCid(kInt32x4Cid);
853 case kTypedDataFloat64x2ArrayCid:
854 return CompileType::FromCid(kFloat64x2Cid);
855
856 case kTypedDataInt8ArrayCid:
857 case kTypedDataUint8ArrayCid:
858 case kTypedDataUint8ClampedArrayCid:
859 case kExternalTypedDataUint8ArrayCid:
860 case kExternalTypedDataUint8ClampedArrayCid:
861 case kTypedDataInt16ArrayCid:
862 case kTypedDataUint16ArrayCid:
863 case kOneByteStringCid:
864 case kTwoByteStringCid:
865 case kTypedDataInt32ArrayCid:
866 case kTypedDataUint32ArrayCid:
867 return CompileType::FromCid(kSmiCid);
868
869 default:
870 UNIMPLEMENTED();
871 return CompileType::Dynamic();
872 }
524 } 873 }
525 874
526 875
527 Representation LoadIndexedInstr::representation() const { 876 Representation LoadIndexedInstr::representation() const {
528 UNIMPLEMENTED(); 877 switch (class_id_) {
529 return kTagged; 878 case kArrayCid:
879 case kImmutableArrayCid:
880 case kTypedDataInt8ArrayCid:
881 case kTypedDataUint8ArrayCid:
882 case kTypedDataUint8ClampedArrayCid:
883 case kExternalTypedDataUint8ArrayCid:
884 case kExternalTypedDataUint8ClampedArrayCid:
885 case kTypedDataInt16ArrayCid:
886 case kTypedDataUint16ArrayCid:
887 case kOneByteStringCid:
888 case kTwoByteStringCid:
889 case kTypedDataInt32ArrayCid:
890 case kTypedDataUint32ArrayCid:
891 return kTagged;
892 case kTypedDataFloat32ArrayCid:
893 case kTypedDataFloat64ArrayCid:
894 return kUnboxedDouble;
895 case kTypedDataInt32x4ArrayCid:
896 return kUnboxedInt32x4;
897 case kTypedDataFloat32x4ArrayCid:
898 return kUnboxedFloat32x4;
899 case kTypedDataFloat64x2ArrayCid:
900 return kUnboxedFloat64x2;
901 default:
902 UNIMPLEMENTED();
903 return kTagged;
904 }
530 } 905 }
531 906
532 907
533 LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const { 908 LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const {
534 UNIMPLEMENTED(); 909 const intptr_t kNumInputs = 2;
535 return NULL; 910 const intptr_t kNumTemps = 0;
911 LocationSummary* locs =
912 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
913 locs->set_in(0, Location::RequiresRegister());
914 // The smi index is either untagged (element size == 1), or it is left smi
915 // tagged (for all element sizes > 1).
916 // TODO(regis): Revisit and see if the index can be immediate.
917 locs->set_in(1, Location::WritableRegister());
918 if ((representation() == kUnboxedDouble) ||
919 (representation() == kUnboxedFloat32x4) ||
920 (representation() == kUnboxedInt32x4) ||
921 (representation() == kUnboxedFloat64x2)) {
922 locs->set_out(0, Location::RequiresFpuRegister());
923 } else {
924 locs->set_out(0, Location::RequiresRegister());
925 }
926 return locs;
536 } 927 }
537 928
538 929
539 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 930 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
540 UNIMPLEMENTED(); 931 Register array = locs()->in(0).reg();
541 } 932 Location index = locs()->in(1);
542 933
543 934 Address element_address(kNoRegister, 0);
935 ASSERT(index.IsRegister()); // TODO(regis): Revisit.
936 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
937 // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
938 // index is expected to be untagged before accessing.
939 ASSERT(kSmiTagShift == 1);
940 switch (index_scale()) {
941 case 1: {
942 __ SmiUntag(index.reg());
943 break;
944 }
945 case 2: {
946 break;
947 }
948 case 4: {
949 __ Lsl(index.reg(), index.reg(), 1);
950 break;
951 }
952 case 8: {
953 __ Lsl(index.reg(), index.reg(), 2);
954 break;
955 }
956 case 16: {
957 __ Lsl(index.reg(), index.reg(), 3);
958 break;
959 }
960 default:
961 UNREACHABLE();
962 }
963
964 if (!IsExternal()) {
965 ASSERT(this->array()->definition()->representation() == kTagged);
966 __ AddImmediate(index.reg(), index.reg(),
967 FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag, PP);
968 }
969 element_address = Address(array, index.reg(), UXTX, Address::Unscaled);
970
971 if ((representation() == kUnboxedDouble) ||
972 (representation() == kUnboxedMint) ||
973 (representation() == kUnboxedFloat32x4) ||
974 (representation() == kUnboxedInt32x4) ||
975 (representation() == kUnboxedFloat64x2)) {
976 const VRegister result = locs()->out(0).fpu_reg();
977 switch (class_id()) {
978 case kTypedDataInt32ArrayCid:
979 case kTypedDataUint32ArrayCid:
980 // TODO(zra): Add when we have simd.
981 UNIMPLEMENTED();
982 break;
983 case kTypedDataFloat32ArrayCid:
984 // Load single precision float.
985 // TODO(zra): Add when we add single precision floats.
986 UNIMPLEMENTED();
987 break;
988 case kTypedDataFloat64ArrayCid:
989 // Load double precision float.
990 __ fldrd(result, element_address);
991 break;
992 case kTypedDataFloat64x2ArrayCid:
993 case kTypedDataInt32x4ArrayCid:
994 case kTypedDataFloat32x4ArrayCid:
995 // TODO(zra): Add when we have simd.
996 UNIMPLEMENTED();
997 break;
998 }
999 return;
1000 }
1001
1002 Register result = locs()->out(0).reg();
1003 switch (class_id()) {
1004 case kTypedDataInt8ArrayCid:
1005 ASSERT(index_scale() == 1);
1006 __ ldr(result, element_address, kByte);
1007 __ SmiTag(result);
1008 break;
1009 case kTypedDataUint8ArrayCid:
1010 case kTypedDataUint8ClampedArrayCid:
1011 case kExternalTypedDataUint8ArrayCid:
1012 case kExternalTypedDataUint8ClampedArrayCid:
1013 case kOneByteStringCid:
1014 ASSERT(index_scale() == 1);
1015 __ ldr(result, element_address, kUnsignedByte);
1016 __ SmiTag(result);
1017 break;
1018 case kTypedDataInt16ArrayCid:
1019 __ ldr(result, element_address, kHalfword);
1020 __ SmiTag(result);
1021 break;
1022 case kTypedDataUint16ArrayCid:
1023 case kTwoByteStringCid:
1024 __ ldr(result, element_address, kUnsignedHalfword);
1025 __ SmiTag(result);
1026 break;
1027 case kTypedDataInt32ArrayCid:
1028 __ ldr(result, element_address, kWord);
1029 __ SmiTag(result);
1030 break;
1031 case kTypedDataUint32ArrayCid:
1032 __ ldr(result, element_address, kUnsignedWord);
1033 break;
1034 default:
1035 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid));
1036 __ ldr(result, element_address);
1037 break;
1038 }
1039 }
1040
1041
544 Representation StoreIndexedInstr::RequiredInputRepresentation( 1042 Representation StoreIndexedInstr::RequiredInputRepresentation(
545 intptr_t idx) const { 1043 intptr_t idx) const {
546 // Array can be a Dart object or a pointer to external data. 1044 // Array can be a Dart object or a pointer to external data.
547 if (idx == 0) return kNoRepresentation; // Flexible input representation. 1045 if (idx == 0) return kNoRepresentation; // Flexible input representation.
548 if (idx == 1) return kTagged; // Index is a smi. 1046 if (idx == 1) return kTagged; // Index is a smi.
549 ASSERT(idx == 2); 1047 ASSERT(idx == 2);
550 switch (class_id_) { 1048 switch (class_id_) {
551 case kArrayCid: 1049 case kArrayCid:
552 case kOneByteStringCid: 1050 case kOneByteStringCid:
553 case kTypedDataInt8ArrayCid: 1051 case kTypedDataInt8ArrayCid:
(...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after
1381 __ StoreIntoObject(temp, 1879 __ StoreIntoObject(temp,
1382 FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi()); 1880 FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
1383 } else { 1881 } else {
1384 __ StoreIntoObjectNoBarrier( 1882 __ StoreIntoObjectNoBarrier(
1385 temp, FieldAddress(temp, Field::value_offset()), value); 1883 temp, FieldAddress(temp, Field::value_offset()), value);
1386 } 1884 }
1387 } 1885 }
1388 1886
1389 1887
1390 LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const { 1888 LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const {
1391 UNIMPLEMENTED(); 1889 const intptr_t kNumInputs = 3;
1392 return NULL; 1890 const intptr_t kNumTemps = 0;
1891 LocationSummary* summary =
1892 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
1893 summary->set_in(0, Location::RegisterLocation(R0));
1894 summary->set_in(1, Location::RegisterLocation(R2));
1895 summary->set_in(2, Location::RegisterLocation(R1));
1896 summary->set_out(0, Location::RegisterLocation(R0));
1897 return summary;
1393 } 1898 }
1394 1899
1395 1900
1396 void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 1901 void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1397 UNIMPLEMENTED(); 1902 ASSERT(locs()->in(0).reg() == R0); // Value.
1903 ASSERT(locs()->in(1).reg() == R2); // Instantiator.
1904 ASSERT(locs()->in(2).reg() == R1); // Instantiator type arguments.
1905
1906 compiler->GenerateInstanceOf(token_pos(),
1907 deopt_id(),
1908 type(),
1909 negate_result(),
1910 locs());
1911 ASSERT(locs()->out(0).reg() == R0);
1398 } 1912 }
1399 1913
1400 1914
1401 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const { 1915 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
1402 const intptr_t kNumInputs = 2; 1916 const intptr_t kNumInputs = 2;
1403 const intptr_t kNumTemps = 0; 1917 const intptr_t kNumTemps = 0;
1404 LocationSummary* locs = 1918 LocationSummary* locs =
1405 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); 1919 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
1406 locs->set_in(kElementTypePos, Location::RegisterLocation(R1)); 1920 locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
1407 locs->set_in(kLengthPos, Location::RegisterLocation(R2)); 1921 locs->set_in(kLengthPos, Location::RegisterLocation(R2));
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1569 } 2083 }
1570 2084
1571 __ Bind(&load_pointer); 2085 __ Bind(&load_pointer);
1572 } 2086 }
1573 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes()); 2087 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes());
1574 __ Bind(&done); 2088 __ Bind(&done);
1575 } 2089 }
1576 2090
1577 2091
1578 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const { 2092 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const {
1579 UNIMPLEMENTED(); 2093 const intptr_t kNumInputs = 1;
1580 return NULL; 2094 const intptr_t kNumTemps = 0;
2095 LocationSummary* locs =
2096 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
2097 locs->set_in(0, Location::RegisterLocation(R0));
2098 locs->set_out(0, Location::RegisterLocation(R0));
2099 return locs;
1581 } 2100 }
1582 2101
1583 2102
1584 void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2103 void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1585 UNIMPLEMENTED(); 2104 Register instantiator_reg = locs()->in(0).reg();
2105 Register result_reg = locs()->out(0).reg();
2106
2107 // 'instantiator_reg' is the instantiator TypeArguments object (or null).
2108 // A runtime call to instantiate the type is required.
2109 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result.
2110 __ PushObject(type(), PP);
2111 __ Push(instantiator_reg); // Push instantiator type arguments.
2112 compiler->GenerateRuntimeCall(token_pos(),
2113 deopt_id(),
2114 kInstantiateTypeRuntimeEntry,
2115 2,
2116 locs());
2117 __ Drop(2); // Drop instantiator and uninstantiated type.
2118 __ Pop(result_reg); // Pop instantiated type.
2119 ASSERT(instantiator_reg == result_reg);
1586 } 2120 }
1587 2121
1588 2122
1589 LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary( 2123 LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
1590 bool opt) const { 2124 bool opt) const {
1591 const intptr_t kNumInputs = 1; 2125 const intptr_t kNumInputs = 1;
1592 const intptr_t kNumTemps = 0; 2126 const intptr_t kNumTemps = 0;
1593 LocationSummary* locs = 2127 LocationSummary* locs =
1594 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); 2128 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
1595 locs->set_in(0, Location::RegisterLocation(R0)); 2129 locs->set_in(0, Location::RegisterLocation(R0));
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
1826 __ CompareImmediate(temp, threshold, PP); 2360 __ CompareImmediate(temp, threshold, PP);
1827 __ b(slow_path->osr_entry_label(), GE); 2361 __ b(slow_path->osr_entry_label(), GE);
1828 } 2362 }
1829 if (compiler->ForceSlowPathForStackOverflow()) { 2363 if (compiler->ForceSlowPathForStackOverflow()) {
1830 __ b(slow_path->entry_label()); 2364 __ b(slow_path->entry_label());
1831 } 2365 }
1832 __ Bind(slow_path->exit_label()); 2366 __ Bind(slow_path->exit_label());
1833 } 2367 }
1834 2368
1835 2369
2370 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
2371 BinarySmiOpInstr* shift_left) {
2372 const bool is_truncating = shift_left->is_truncating();
2373 const LocationSummary& locs = *shift_left->locs();
2374 Register left = locs.in(0).reg();
2375 Register result = locs.out(0).reg();
2376 Label* deopt = shift_left->CanDeoptimize() ?
2377 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp)
2378 : NULL;
2379 if (locs.in(1).IsConstant()) {
2380 const Object& constant = locs.in(1).constant();
2381 ASSERT(constant.IsSmi());
2382 // Immediate shift operation takes 6 bits for the count.
2383 const intptr_t kCountLimit = 0x3F;
2384 const intptr_t value = Smi::Cast(constant).Value();
2385 if (value == 0) {
2386 __ mov(result, left);
2387 } else if ((value < 0) || (value >= kCountLimit)) {
2388 // This condition may not be known earlier in some cases because
2389 // of constant propagation, inlining, etc.
2390 if ((value >= kCountLimit) && is_truncating) {
2391 __ mov(result, ZR);
2392 } else {
2393 // Result is Mint or exception.
2394 __ b(deopt);
2395 }
2396 } else {
2397 if (!is_truncating) {
2398 // Check for overflow (preserve left).
2399 __ Lsl(TMP, left, value);
2400 __ cmp(left, Operand(TMP, ASR, value));
2401 __ b(deopt, NE); // Overflow.
2402 }
2403 // Shift for result now we know there is no overflow.
2404 __ Lsl(result, left, value);
2405 }
2406 return;
2407 }
2408
2409 // Right (locs.in(1)) is not constant.
2410 Register right = locs.in(1).reg();
2411 Range* right_range = shift_left->right()->definition()->range();
2412 if (shift_left->left()->BindsToConstant() && !is_truncating) {
2413 // TODO(srdjan): Implement code below for is_truncating().
2414 // If left is constant, we know the maximal allowed size for right.
2415 const Object& obj = shift_left->left()->BoundConstant();
2416 if (obj.IsSmi()) {
2417 const intptr_t left_int = Smi::Cast(obj).Value();
2418 if (left_int == 0) {
2419 __ CompareRegisters(right, ZR);
2420 __ b(deopt, MI);
2421 __ mov(result, ZR);
2422 return;
2423 }
2424 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
2425 const bool right_needs_check =
2426 (right_range == NULL) ||
2427 !right_range->IsWithin(0, max_right - 1);
2428 if (right_needs_check) {
2429 __ CompareImmediate(right,
2430 reinterpret_cast<int64_t>(Smi::New(max_right)), PP);
2431 __ b(deopt, CS);
2432 }
2433 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP.
2434 __ lslv(result, left, TMP);
2435 }
2436 return;
2437 }
2438
2439 const bool right_needs_check =
2440 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
2441 if (is_truncating) {
2442 if (right_needs_check) {
2443 const bool right_may_be_negative =
2444 (right_range == NULL) ||
2445 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
2446 if (right_may_be_negative) {
2447 ASSERT(shift_left->CanDeoptimize());
2448 __ CompareRegisters(right, ZR);
2449 __ b(deopt, MI);
2450 }
2451
2452 __ CompareImmediate(
2453 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP);
2454 __ csel(result, ZR, result, CS);
2455 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP.
2456 __ lslv(TMP, left, TMP);
2457 __ csel(result, TMP, result, CC);
2458 } else {
2459 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP.
2460 __ lslv(result, left, TMP);
2461 }
2462 } else {
2463 if (right_needs_check) {
2464 ASSERT(shift_left->CanDeoptimize());
2465 __ CompareImmediate(
2466 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP);
2467 __ b(deopt, CS);
2468 }
2469 // Left is not a constant.
2470 // Check if count too large for handling it inlined.
2471 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP.
2472 // Overflow test (preserve left, right, and IP);
2473 Register temp = locs.temp(0).reg();
2474 __ lslv(temp, left, TMP);
2475 __ asrv(TMP2, temp, TMP);
2476 __ CompareRegisters(left, TMP2);
2477 __ b(deopt, NE); // Overflow.
2478 // Shift for result now we know there is no overflow.
2479 __ lslv(result, left, TMP);
2480 }
2481 }
2482
2483
1836 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { 2484 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const {
1837 UNIMPLEMENTED(); 2485 const intptr_t kNumInputs = 2;
1838 return NULL; 2486 const intptr_t kNumTemps = 0;
2487 LocationSummary* summary =
2488 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2489 if (op_kind() == Token::kTRUNCDIV) {
2490 summary->set_in(0, Location::RequiresRegister());
2491 if (RightIsPowerOfTwoConstant()) {
2492 ConstantInstr* right_constant = right()->definition()->AsConstant();
2493 summary->set_in(1, Location::Constant(right_constant->value()));
2494 } else {
2495 summary->set_in(1, Location::RequiresRegister());
2496 }
2497 summary->set_out(0, Location::RequiresRegister());
2498 return summary;
2499 }
2500 if (op_kind() == Token::kMOD) {
2501 summary->set_in(0, Location::RequiresRegister());
2502 summary->set_in(1, Location::RequiresRegister());
2503 summary->set_out(0, Location::RequiresRegister());
2504 return summary;
2505 }
2506 summary->set_in(0, Location::RequiresRegister());
2507 summary->set_in(1, Location::RegisterOrSmiConstant(right()));
2508 if (((op_kind() == Token::kSHL) && !is_truncating()) ||
2509 (op_kind() == Token::kSHR)) {
2510 summary->AddTemp(Location::RequiresRegister());
2511 }
2512 // We make use of 3-operand instructions by not requiring result register
2513 // to be identical to first input register as on Intel.
2514 summary->set_out(0, Location::RequiresRegister());
2515 return summary;
1839 } 2516 }
1840 2517
1841 2518
1842 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2519 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1843 UNIMPLEMENTED(); 2520 if (op_kind() == Token::kSHL) {
2521 EmitSmiShiftLeft(compiler, this);
2522 return;
2523 }
2524
2525 ASSERT(!is_truncating());
2526 const Register left = locs()->in(0).reg();
2527 const Register result = locs()->out(0).reg();
2528 Label* deopt = NULL;
2529 if (CanDeoptimize()) {
2530 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
2531 }
2532
2533 if (locs()->in(1).IsConstant()) {
2534 const Object& constant = locs()->in(1).constant();
2535 ASSERT(constant.IsSmi());
2536 int64_t imm = reinterpret_cast<int64_t>(constant.raw());
2537 switch (op_kind()) {
2538 case Token::kSUB: {
2539 imm = -imm; // TODO(regis): What if deopt != NULL && imm == 0x80000000?
2540 // Fall through.
2541 }
2542 case Token::kADD: {
2543 if (deopt == NULL) {
2544 __ AddImmediate(result, left, imm, PP);
2545 } else {
2546 __ AddImmediateSetFlags(result, left, imm, PP);
2547 __ b(deopt, VS); }
2548 break;
2549 }
2550 case Token::kMUL: {
2551 // Keep left value tagged and untag right value.
2552 const intptr_t value = Smi::Cast(constant).Value();
2553 if (deopt == NULL) {
2554 if (value == 2) {
2555 __ Lsl(result, left, 1);
2556 } else {
2557 __ LoadImmediate(TMP, value, PP);
2558 __ mul(result, left, TMP);
2559 }
2560 } else {
2561 if (value == 2) {
2562 __ Asr(TMP, left, 63); // TMP = sign of left.
2563 __ Lsl(result, left, 1);
2564 // TMP: result bits 32..63.
2565 __ cmp(TMP, Operand(result, ASR, 63));
2566 __ b(deopt, NE);
2567 } else {
2568 __ LoadImmediate(TMP, value, PP);
2569 __ mul(result, left, TMP);
2570 __ smulh(TMP, left, TMP);
2571 // TMP: result bits 64..127.
2572 __ cmp(TMP, Operand(result, ASR, 63));
2573 __ b(deopt, NE);
2574 }
2575 }
2576 break;
2577 }
2578 case Token::kTRUNCDIV: {
2579 const intptr_t value = Smi::Cast(constant).Value();
2580 if (value == 1) {
2581 __ mov(result, left);
2582 break;
2583 } else if (value == -1) {
2584 // Check the corner case of dividing the 'MIN_SMI' with -1, in which
2585 // case we cannot negate the result.
2586 __ CompareImmediate(left, 0x8000000000000000LL, kNoPP);
2587 __ b(deopt, EQ);
2588 __ sub(result, ZR, Operand(left));
2589 break;
2590 }
2591 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value)));
2592 const intptr_t shift_count =
2593 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
2594 ASSERT(kSmiTagSize == 1);
2595 __ Asr(TMP, left, 63);
2596 ASSERT(shift_count > 1); // 1, -1 case handled above.
2597 const Register temp = TMP2;
2598 __ add(temp, left, Operand(TMP, LSR, 64 - shift_count));
2599 ASSERT(shift_count > 0);
2600 __ Asr(result, temp, shift_count);
2601 if (value < 0) {
2602 __ sub(result, ZR, Operand(result));
2603 }
2604 __ SmiTag(result);
2605 break;
2606 }
2607 case Token::kBIT_AND:
2608 // No overflow check.
2609 __ AndImmediate(result, left, imm, PP);
2610 break;
2611 case Token::kBIT_OR:
2612 // No overflow check.
2613 __ OrImmediate(result, left, imm, PP);
2614 break;
2615 case Token::kBIT_XOR:
2616 // No overflow check.
2617 __ XorImmediate(result, left, imm, PP);
2618 break;
2619 case Token::kSHR: {
2620 // Asr operation masks the count to 6 bits.
2621 const intptr_t kCountLimit = 0x3F;
2622 intptr_t value = Smi::Cast(constant).Value();
2623
2624 if (value == 0) {
2625 // TODO(vegorov): should be handled outside.
2626 __ mov(result, left);
2627 break;
2628 } else if (value < 0) {
2629 // TODO(vegorov): should be handled outside.
2630 __ b(deopt);
2631 break;
2632 }
2633
2634 value = value + kSmiTagSize;
2635 if (value >= kCountLimit) {
2636 value = kCountLimit;
2637 }
2638
2639 __ Asr(result, left, value);
2640 __ SmiTag(result);
2641 break;
2642 }
2643 default:
2644 UNREACHABLE();
2645 break;
2646 }
2647 return;
2648 }
2649
2650 Register right = locs()->in(1).reg();
2651 Range* right_range = this->right()->definition()->range();
2652 switch (op_kind()) {
2653 case Token::kADD: {
2654 if (deopt == NULL) {
2655 __ add(result, left, Operand(right));
2656 } else {
2657 __ adds(result, left, Operand(right));
2658 __ b(deopt, VS);
2659 }
2660 break;
2661 }
2662 case Token::kSUB: {
2663 if (deopt == NULL) {
2664 __ sub(result, left, Operand(right));
2665 } else {
2666 __ subs(result, left, Operand(right));
2667 __ b(deopt, VS);
2668 }
2669 break;
2670 }
2671 case Token::kMUL: {
2672 __ Asr(TMP, left, kSmiTagSize); // SmiUntag left into TMP.
2673 if (deopt == NULL) {
2674 __ mul(result, TMP, right);
2675 } else {
2676 __ mul(result, TMP, right);
2677 __ smulh(TMP, TMP, right);
2678 // TMP: result bits 64..127.
2679 __ cmp(TMP, Operand(result, ASR, 63));
2680 __ b(deopt, NE);
2681 }
2682 break;
2683 }
2684 case Token::kBIT_AND: {
2685 // No overflow check.
2686 __ and_(result, left, Operand(right));
2687 break;
2688 }
2689 case Token::kBIT_OR: {
2690 // No overflow check.
2691 __ orr(result, left, Operand(right));
2692 break;
2693 }
2694 case Token::kBIT_XOR: {
2695 // No overflow check.
2696 __ eor(result, left, Operand(right));
2697 break;
2698 }
2699 case Token::kTRUNCDIV: {
2700 if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
2701 // Handle divide by zero in runtime.
2702 __ CompareRegisters(right, ZR);
2703 __ b(deopt, EQ);
2704 }
2705 const Register temp = TMP2;
2706 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp.
2707 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP.
2708
2709 __ sdiv(result, temp, TMP);
2710
2711 // Check the corner case of dividing the 'MIN_SMI' with -1, in which
2712 // case we cannot tag the result.
2713 __ CompareImmediate(result, 0x4000000000000000LL, kNoPP);
2714 __ b(deopt, EQ);
2715 __ SmiTag(result);
2716 break;
2717 }
2718 case Token::kMOD: {
2719 if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
2720 // Handle divide by zero in runtime.
2721 __ CompareRegisters(right, ZR);
2722 __ b(deopt, EQ);
2723 }
2724 const Register temp = TMP2;
2725 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp.
2726 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP.
2727
2728 __ sdiv(result, temp, TMP);
2729
2730 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP.
2731 __ msub(result, TMP, result, temp); // result <- left - right * result
2732 __ SmiTag(result);
2733 // res = left % right;
2734 // if (res < 0) {
2735 // if (right < 0) {
2736 // res = res - right;
2737 // } else {
2738 // res = res + right;
2739 // }
2740 // }
2741 Label done;
2742 __ CompareRegisters(result, ZR);
2743 __ b(&done, GE);
2744 // Result is negative, adjust it.
2745 __ CompareRegisters(right, ZR);
2746 __ sub(TMP, result, Operand(right));
2747 __ add(result, result, Operand(right));
2748 __ csel(result, TMP, result, LT);
2749 __ Bind(&done);
2750 break;
2751 }
2752 case Token::kSHR: {
2753 if (CanDeoptimize()) {
2754 __ CompareRegisters(right, ZR);
2755 __ b(deopt, LT);
2756 }
2757 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP.
2758 // sarl operation masks the count to 6 bits.
2759 const intptr_t kCountLimit = 0x3F;
2760 if ((right_range == NULL) ||
2761 !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) {
2762 __ LoadImmediate(TMP2, kCountLimit, PP);
2763 __ CompareRegisters(TMP, TMP2);
2764 __ csel(TMP, TMP2, TMP, GT);
2765 }
2766 Register temp = locs()->temp(0).reg();
2767 __ Asr(temp, left, kSmiTagSize); // SmiUntag left into temp.
2768 __ Asr(result, temp, TMP);
2769 __ SmiTag(result);
2770 break;
2771 }
2772 case Token::kDIV: {
2773 // Dispatches to 'Double./'.
2774 // TODO(srdjan): Implement as conversion to double and double division.
2775 UNREACHABLE();
2776 break;
2777 }
2778 case Token::kOR:
2779 case Token::kAND: {
2780 // Flow graph builder has dissected this operation to guarantee correct
2781 // behavior (short-circuit evaluation).
2782 UNREACHABLE();
2783 break;
2784 }
2785 default:
2786 UNREACHABLE();
2787 break;
2788 }
1844 } 2789 }
1845 2790
1846 2791
1847 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { 2792 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const {
1848 UNIMPLEMENTED(); 2793 UNIMPLEMENTED();
1849 return NULL; 2794 return NULL;
1850 } 2795 }
1851 2796
1852 2797
1853 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2798 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1854 UNIMPLEMENTED(); 2799 UNIMPLEMENTED();
1855 } 2800 }
1856 2801
1857 2802
1858 LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const { 2803 LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const {
1859 UNIMPLEMENTED(); 2804 const intptr_t kNumInputs = 1;
1860 return NULL; 2805 const intptr_t kNumTemps = 1;
2806 LocationSummary* summary =
2807 new LocationSummary(kNumInputs,
2808 kNumTemps,
2809 LocationSummary::kCallOnSlowPath);
2810 summary->set_in(0, Location::RequiresFpuRegister());
2811 summary->set_temp(0, Location::RequiresRegister());
2812 summary->set_out(0, Location::RequiresRegister());
2813 return summary;
1861 } 2814 }
1862 2815
1863 2816
1864 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2817 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1865 UNIMPLEMENTED(); 2818 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
2819 compiler->AddSlowPathCode(slow_path);
2820
2821 const Register out_reg = locs()->out(0).reg();
2822 const VRegister value = locs()->in(0).fpu_reg();
2823
2824 __ TryAllocate(compiler->double_class(),
2825 slow_path->entry_label(),
2826 out_reg,
2827 locs()->temp(0).reg(),
2828 PP);
2829 __ Bind(slow_path->exit_label());
2830 __ StoreDFieldToOffset(value, out_reg, Double::value_offset());
1866 } 2831 }
1867 2832
1868 2833
1869 LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const { 2834 LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const {
1870 UNIMPLEMENTED(); 2835 UNIMPLEMENTED();
1871 return NULL; 2836 return NULL;
1872 } 2837 }
1873 2838
1874 2839
1875 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2840 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after
2305 return NULL; 3270 return NULL;
2306 } 3271 }
2307 3272
2308 3273
2309 void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3274 void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2310 UNIMPLEMENTED(); 3275 UNIMPLEMENTED();
2311 } 3276 }
2312 3277
2313 3278
2314 LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const { 3279 LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const {
2315 UNIMPLEMENTED(); 3280 const intptr_t kNumInputs = 1;
2316 return NULL; 3281 const intptr_t kNumTemps = 0;
3282 LocationSummary* summary =
3283 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3284 summary->set_in(0, Location::RequiresRegister());
3285 // We make use of 3-operand instructions by not requiring result register
3286 // to be identical to first input register as on Intel.
3287 summary->set_out(0, Location::RequiresRegister());
3288 return summary;
2317 } 3289 }
2318 3290
2319 3291
2320 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3292 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2321 UNIMPLEMENTED(); 3293 Register value = locs()->in(0).reg();
3294 Register result = locs()->out(0).reg();
3295 switch (op_kind()) {
3296 case Token::kNEGATE: {
3297 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
3298 __ subs(result, ZR, Operand(value));
3299 __ b(deopt, VS);
3300 break;
3301 }
3302 case Token::kBIT_NOT:
3303 __ mvn(result, value);
3304 // Remove inverted smi-tag.
3305 __ andi(result, result, ~kSmiTagMask);
3306 break;
3307 default:
3308 UNREACHABLE();
3309 }
2322 } 3310 }
2323 3311
2324 3312
2325 LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const { 3313 LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
2326 UNIMPLEMENTED(); 3314 UNIMPLEMENTED();
2327 return NULL; 3315 return NULL;
2328 } 3316 }
2329 3317
2330 3318
2331 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3319 void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
2404 return NULL; 3392 return NULL;
2405 } 3393 }
2406 3394
2407 3395
2408 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3396 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2409 UNIMPLEMENTED(); 3397 UNIMPLEMENTED();
2410 } 3398 }
2411 3399
2412 3400
2413 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { 3401 LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const {
2414 UNIMPLEMENTED(); 3402 // Only use this instruction in optimized code.
2415 return NULL; 3403 ASSERT(opt);
3404 const intptr_t kNumInputs = 1;
3405 LocationSummary* summary =
3406 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
3407 if (representation() == kUnboxedDouble) {
3408 if (index() == 0) {
3409 summary->set_in(0, Location::Pair(Location::RequiresFpuRegister(),
3410 Location::Any()));
3411 } else {
3412 ASSERT(index() == 1);
3413 summary->set_in(0, Location::Pair(Location::Any(),
3414 Location::RequiresFpuRegister()));
3415 }
3416 summary->set_out(0, Location::RequiresFpuRegister());
3417 } else {
3418 ASSERT(representation() == kTagged);
3419 if (index() == 0) {
3420 summary->set_in(0, Location::Pair(Location::RequiresRegister(),
3421 Location::Any()));
3422 } else {
3423 ASSERT(index() == 1);
3424 summary->set_in(0, Location::Pair(Location::Any(),
3425 Location::RequiresRegister()));
3426 }
3427 summary->set_out(0, Location::RequiresRegister());
3428 }
3429 return summary;
2416 } 3430 }
2417 3431
2418 3432
2419 void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3433 void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2420 UNIMPLEMENTED(); 3434 ASSERT(locs()->in(0).IsPairLocation());
3435 PairLocation* pair = locs()->in(0).AsPairLocation();
3436 Location in_loc = pair->At(index());
3437 if (representation() == kUnboxedDouble) {
3438 VRegister out = locs()->out(0).fpu_reg();
3439 VRegister in = in_loc.fpu_reg();
3440 __ fmovdd(out, in);
3441 } else {
3442 ASSERT(representation() == kTagged);
3443 Register out = locs()->out(0).reg();
3444 Register in = in_loc.reg();
3445 __ mov(out, in);
3446 }
2421 } 3447 }
2422 3448
2423 3449
2424 LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const { 3450 LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const {
2425 UNIMPLEMENTED(); 3451 UNIMPLEMENTED();
2426 return NULL; 3452 return NULL;
2427 } 3453 }
2428 3454
2429 3455
2430 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3456 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2431 UNIMPLEMENTED(); 3457 UNIMPLEMENTED();
2432 } 3458 }
2433 3459
2434 3460
2435 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( 3461 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(
2436 bool opt) const { 3462 bool opt) const {
2437 UNIMPLEMENTED(); 3463 return MakeCallSummary();
2438 return NULL;
2439 } 3464 }
2440 3465
2441 3466
2442 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3467 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2443 UNIMPLEMENTED(); 3468 Label* deopt = compiler->AddDeoptStub(
3469 deopt_id(), ICData::kDeoptPolymorphicInstanceCallTestFail);
3470 if (ic_data().NumberOfChecks() == 0) {
3471 __ b(deopt);
3472 return;
3473 }
3474 ASSERT(ic_data().NumArgsTested() == 1);
3475 if (!with_checks()) {
3476 ASSERT(ic_data().HasOneTarget());
3477 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
3478 compiler->GenerateStaticCall(deopt_id(),
3479 instance_call()->token_pos(),
3480 target,
3481 instance_call()->ArgumentCount(),
3482 instance_call()->argument_names(),
3483 locs());
3484 return;
3485 }
3486
3487 // Load receiver into R0.
3488 __ LoadFromOffset(
3489 R0, SP, (instance_call()->ArgumentCount() - 1) * kWordSize);
3490
3491 LoadValueCid(compiler, R2, R0,
3492 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
3493
3494 compiler->EmitTestAndCall(ic_data(),
3495 R2, // Class id register.
3496 instance_call()->ArgumentCount(),
3497 instance_call()->argument_names(),
3498 deopt,
3499 deopt_id(),
3500 instance_call()->token_pos(),
3501 locs());
2444 } 3502 }
2445 3503
2446 3504
2447 LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const { 3505 LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const {
2448 comparison()->InitializeLocationSummary(opt); 3506 comparison()->InitializeLocationSummary(opt);
2449 // Branches don't produce a result. 3507 // Branches don't produce a result.
2450 comparison()->locs()->set_out(0, Location::NoLocation()); 3508 comparison()->locs()->set_out(0, Location::NoLocation());
2451 return comparison()->locs(); 3509 return comparison()->locs();
2452 } 3510 }
2453 3511
2454 3512
2455 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3513 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2456 comparison()->EmitBranchCode(compiler, this); 3514 comparison()->EmitBranchCode(compiler, this);
2457 } 3515 }
2458 3516
2459 3517
2460 LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const { 3518 LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
2461 UNIMPLEMENTED(); 3519 const intptr_t kNumInputs = 1;
2462 return NULL; 3520 const intptr_t kNumTemps = 0;
3521 LocationSummary* summary =
3522 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3523 summary->set_in(0, Location::RequiresRegister());
3524 if (!IsNullCheck()) {
3525 summary->AddTemp(Location::RequiresRegister());
3526 }
3527 return summary;
2463 } 3528 }
2464 3529
2465 3530
2466 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3531 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2467 UNIMPLEMENTED(); 3532 const ICData::DeoptReasonId deopt_reason = licm_hoisted_ ?
3533 ICData::kDeoptHoistedCheckClass : ICData::kDeoptCheckClass;
3534 if (IsNullCheck()) {
3535 Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
3536 __ CompareObject(locs()->in(0).reg(), Object::null_object(), PP);
3537 __ b(deopt, EQ);
3538 return;
3539 }
3540
3541 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) ||
3542 (unary_checks().NumberOfChecks() > 1));
3543 Register value = locs()->in(0).reg();
3544 Register temp = locs()->temp(0).reg();
3545 Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
3546 Label is_ok;
3547 intptr_t cix = 0;
3548 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
3549 __ tsti(value, kSmiTagMask);
3550 __ b(&is_ok, EQ);
3551 cix++; // Skip first check.
3552 } else {
3553 __ tsti(value, kSmiTagMask);
3554 __ b(deopt, EQ);
3555 }
3556 __ LoadClassId(temp, value);
3557 const intptr_t num_checks = unary_checks().NumberOfChecks();
3558 for (intptr_t i = cix; i < num_checks; i++) {
3559 ASSERT(unary_checks().GetReceiverClassIdAt(i) != kSmiCid);
3560 __ CompareImmediate(temp, unary_checks().GetReceiverClassIdAt(i), PP);
3561 if (i == (num_checks - 1)) {
3562 __ b(deopt, NE);
3563 } else {
3564 __ b(&is_ok, EQ);
3565 }
3566 }
3567 __ Bind(&is_ok);
2468 } 3568 }
2469 3569
2470 3570
2471 LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const { 3571 LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const {
2472 UNIMPLEMENTED(); 3572 const intptr_t kNumInputs = 1;
2473 return NULL; 3573 const intptr_t kNumTemps = 0;
3574 LocationSummary* summary =
3575 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3576 summary->set_in(0, Location::RequiresRegister());
3577 return summary;
2474 } 3578 }
2475 3579
2476 3580
2477 void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3581 void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2478 UNIMPLEMENTED(); 3582 Register value = locs()->in(0).reg();
3583 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckSmi);
3584 __ tsti(value, kSmiTagMask);
3585 __ b(deopt, NE);
2479 } 3586 }
2480 3587
2481 3588
2482 LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const { 3589 LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const {
2483 UNIMPLEMENTED(); 3590 const intptr_t kNumInputs = 2;
2484 return NULL; 3591 const intptr_t kNumTemps = 0;
3592 LocationSummary* locs =
3593 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3594 locs->set_in(kLengthPos, Location::RegisterOrSmiConstant(length()));
3595 locs->set_in(kIndexPos, Location::RegisterOrSmiConstant(index()));
3596 return locs;
2485 } 3597 }
2486 3598
2487 3599
2488 void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3600 void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2489 UNIMPLEMENTED(); 3601 Label* deopt = compiler->AddDeoptStub(deopt_id(),
3602 ICData::kDeoptCheckArrayBound);
3603
3604 Location length_loc = locs()->in(kLengthPos);
3605 Location index_loc = locs()->in(kIndexPos);
3606
3607 if (length_loc.IsConstant() && index_loc.IsConstant()) {
3608 // TODO(srdjan): remove this code once failures are fixed.
3609 if ((Smi::Cast(length_loc.constant()).Value() >
3610 Smi::Cast(index_loc.constant()).Value()) &&
3611 (Smi::Cast(index_loc.constant()).Value() >= 0)) {
3612 // This CheckArrayBoundInstr should have been eliminated.
3613 return;
3614 }
3615 ASSERT((Smi::Cast(length_loc.constant()).Value() <=
3616 Smi::Cast(index_loc.constant()).Value()) ||
3617 (Smi::Cast(index_loc.constant()).Value() < 0));
3618 // Unconditionally deoptimize for constant bounds checks because they
3619 // only occur only when index is out-of-bounds.
3620 __ b(deopt);
3621 return;
3622 }
3623
3624 if (index_loc.IsConstant()) {
3625 Register length = length_loc.reg();
3626 const Smi& index = Smi::Cast(index_loc.constant());
3627 __ CompareImmediate(length, reinterpret_cast<int64_t>(index.raw()), PP);
3628 __ b(deopt, LS);
3629 } else if (length_loc.IsConstant()) {
3630 const Smi& length = Smi::Cast(length_loc.constant());
3631 Register index = index_loc.reg();
3632 __ CompareImmediate(index, reinterpret_cast<int64_t>(length.raw()), PP);
3633 __ b(deopt, CS);
3634 } else {
3635 Register length = length_loc.reg();
3636 Register index = index_loc.reg();
3637 __ CompareRegisters(index, length);
3638 __ b(deopt, CS);
3639 }
2490 } 3640 }
2491 3641
2492 3642
2493 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const { 3643 LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const {
2494 UNIMPLEMENTED(); 3644 UNIMPLEMENTED();
2495 return NULL; 3645 return NULL;
2496 } 3646 }
2497 3647
2498 3648
2499 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3649 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
2635 Location::RequiresRegister(), 3785 Location::RequiresRegister(),
2636 LocationSummary::kNoCall); 3786 LocationSummary::kNoCall);
2637 } 3787 }
2638 3788
2639 3789
2640 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3790 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2641 __ mov(locs()->out(0).reg(), CTX); 3791 __ mov(locs()->out(0).reg(), CTX);
2642 } 3792 }
2643 3793
2644 3794
2645 static Condition NegateCondition(Condition condition) {
2646 switch (condition) {
2647 case EQ: return NE;
2648 case NE: return EQ;
2649 case LT: return GE;
2650 case LE: return GT;
2651 case GT: return LE;
2652 case GE: return LT;
2653 case CC: return CS;
2654 case LS: return HI;
2655 case HI: return LS;
2656 case CS: return CC;
2657 default:
2658 UNREACHABLE();
2659 return EQ;
2660 }
2661 }
2662
2663
2664 static void EmitBranchOnCondition(FlowGraphCompiler* compiler,
2665 Condition true_condition,
2666 BranchLabels labels) {
2667 if (labels.fall_through == labels.false_label) {
2668 // If the next block is the false successor we will fall through to it.
2669 __ b(labels.true_label, true_condition);
2670 } else {
2671 // If the next block is not the false successor we will branch to it.
2672 Condition false_condition = NegateCondition(true_condition);
2673 __ b(labels.false_label, false_condition);
2674
2675 // Fall through or jump to the true successor.
2676 if (labels.fall_through != labels.true_label) {
2677 __ b(labels.true_label);
2678 }
2679 }
2680 }
2681
2682
2683 LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const { 3795 LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const {
2684 const intptr_t kNumInputs = 2; 3796 const intptr_t kNumInputs = 2;
2685 const intptr_t kNumTemps = 0; 3797 const intptr_t kNumTemps = 0;
2686 if (needs_number_check()) { 3798 if (needs_number_check()) {
2687 LocationSummary* locs = 3799 LocationSummary* locs =
2688 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); 3800 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
2689 locs->set_in(0, Location::RegisterLocation(R0)); 3801 locs->set_in(0, Location::RegisterLocation(R0));
2690 locs->set_in(1, Location::RegisterLocation(R1)); 3802 locs->set_in(1, Location::RegisterLocation(R1));
2691 locs->set_out(0, Location::RegisterLocation(R0)); 3803 locs->set_out(0, Location::RegisterLocation(R0));
2692 return locs; 3804 return locs;
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
2789 compiler->GenerateCall(token_pos(), 3901 compiler->GenerateCall(token_pos(),
2790 &label, 3902 &label,
2791 PcDescriptors::kOther, 3903 PcDescriptors::kOther,
2792 locs()); 3904 locs());
2793 __ Drop(ArgumentCount()); // Discard arguments. 3905 __ Drop(ArgumentCount()); // Discard arguments.
2794 } 3906 }
2795 3907
2796 } // namespace dart 3908 } // namespace dart
2797 3909
2798 #endif // defined TARGET_ARCH_ARM64 3910 #endif // defined TARGET_ARCH_ARM64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.cc ('k') | runtime/vm/simulator_arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698