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

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