OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 __ BranchEqual(CMPRES1, Immediate(fp_sp_dist), &stack_ok); | 108 __ BranchEqual(CMPRES1, Immediate(fp_sp_dist), &stack_ok); |
109 __ break_(0); | 109 __ break_(0); |
110 | 110 |
111 __ Bind(&stack_ok); | 111 __ Bind(&stack_ok); |
112 #endif | 112 #endif |
113 __ LeaveDartFrameAndReturn(); | 113 __ LeaveDartFrameAndReturn(); |
114 } | 114 } |
115 | 115 |
116 | 116 |
117 static Condition NegateCondition(Condition condition) { | 117 static Condition NegateCondition(Condition condition) { |
118 switch (condition) { | 118 switch (condition.rel_op()) { |
119 case EQ: return NE; | 119 case AL: condition.set_rel_op(NV); break; |
120 case NE: return EQ; | 120 case NV: condition.set_rel_op(AL); break; |
121 case LT: return GE; | 121 case EQ: condition.set_rel_op(NE); break; |
122 case LE: return GT; | 122 case NE: condition.set_rel_op(EQ); break; |
123 case GT: return LE; | 123 case LT: condition.set_rel_op(GE); break; |
124 case GE: return LT; | 124 case LE: condition.set_rel_op(GT); break; |
| 125 case GT: condition.set_rel_op(LE); break; |
| 126 case GE: condition.set_rel_op(LT); break; |
| 127 case ULT: condition.set_rel_op(UGE); break; |
| 128 case ULE: condition.set_rel_op(UGT); break; |
| 129 case UGT: condition.set_rel_op(ULE); break; |
| 130 case UGE: condition.set_rel_op(ULT); break; |
125 default: | 131 default: |
126 UNREACHABLE(); | 132 UNREACHABLE(); |
127 return EQ; | |
128 } | 133 } |
129 } | 134 return condition; |
130 | |
131 | |
132 // Detect pattern when one value is zero and another is a power of 2. | |
133 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { | |
134 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || | |
135 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); | |
136 } | 135 } |
137 | 136 |
138 | 137 |
139 LocationSummary* IfThenElseInstr::MakeLocationSummary(Isolate* isolate, | 138 LocationSummary* IfThenElseInstr::MakeLocationSummary(Isolate* isolate, |
140 bool opt) const { | 139 bool opt) const { |
141 comparison()->InitializeLocationSummary(isolate, opt); | 140 comparison()->InitializeLocationSummary(isolate, opt); |
142 return comparison()->locs(); | 141 return comparison()->locs(); |
143 } | 142 } |
144 | 143 |
145 | 144 |
146 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 145 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
147 const Register result = locs()->out(0).reg(); | 146 const Register result = locs()->out(0).reg(); |
148 | 147 |
149 Location left = locs()->in(0); | 148 intptr_t true_value = if_true_; |
150 Location right = locs()->in(1); | 149 intptr_t false_value = if_false_; |
151 ASSERT(!left.IsConstant() || !right.IsConstant()); | 150 bool swapped = false; |
| 151 if (true_value == 0) { |
| 152 // Swap values so that false_value is zero. |
| 153 intptr_t temp = true_value; |
| 154 true_value = false_value; |
| 155 false_value = temp; |
| 156 swapped = true; |
| 157 } |
152 | 158 |
153 // Clear out register. | 159 // Initialize result with the true value. |
154 __ mov(result, ZR); | 160 __ LoadImmediate(result, Smi::RawValue(true_value)); |
155 | 161 |
156 // Emit comparison code. This must not overwrite the result register. | 162 // Emit comparison code. This must not overwrite the result register. |
157 BranchLabels labels = { NULL, NULL, NULL }; | 163 BranchLabels labels = { NULL, NULL, NULL }; // Emit branch-free code. |
158 Condition true_condition = comparison()->EmitComparisonCode(compiler, labels); | 164 Condition true_condition = comparison()->EmitComparisonCode(compiler, labels); |
159 | 165 if (swapped) { |
160 const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_); | 166 true_condition = NegateCondition(true_condition); |
161 | |
162 intptr_t true_value = if_true_; | |
163 intptr_t false_value = if_false_; | |
164 | |
165 if (is_power_of_two_kind) { | |
166 if (true_value == 0) { | |
167 // We need to have zero in result on true_condition. | |
168 true_condition = NegateCondition(true_condition); | |
169 } | |
170 } else { | |
171 if (true_value == 0) { | |
172 // Swap values so that false_value is zero. | |
173 intptr_t temp = true_value; | |
174 true_value = false_value; | |
175 false_value = temp; | |
176 } else { | |
177 true_condition = NegateCondition(true_condition); | |
178 } | |
179 } | 167 } |
180 | 168 |
181 switch (true_condition) { | 169 // Evaluate condition and provide result in CMPRES1. |
| 170 Register left = true_condition.left(); |
| 171 Register right = true_condition.right(); |
| 172 bool zero_is_false = true; // Zero in CMPRES1 indicates a false condition. |
| 173 switch (true_condition.rel_op()) { |
| 174 case AL: return; // Result holds true_value. |
| 175 case NV: __ LoadImmediate(result, false_value); return; |
182 case EQ: | 176 case EQ: |
183 __ xor_(result, CMPRES1, CMPRES2); | 177 zero_is_false = false; |
184 __ xori(result, result, Immediate(1)); | 178 // fall through. |
| 179 case NE: { |
| 180 if (left == IMM) { |
| 181 __ XorImmediate(CMPRES1, right, true_condition.imm()); |
| 182 } else if (right == IMM) { |
| 183 __ XorImmediate(CMPRES1, left, true_condition.imm()); |
| 184 } else { |
| 185 __ xor_(CMPRES1, left, right); |
| 186 } |
185 break; | 187 break; |
186 case NE: | 188 } |
187 __ xor_(result, CMPRES1, CMPRES2); | 189 case GE: |
| 190 zero_is_false = false; |
| 191 // fall through. |
| 192 case LT: { |
| 193 if (left == IMM) { |
| 194 __ slti(CMPRES1, right, Immediate(true_condition.imm() + 1)); |
| 195 zero_is_false = !zero_is_false; |
| 196 } else if (right == IMM) { |
| 197 __ slti(CMPRES1, left, Immediate(true_condition.imm())); |
| 198 } else { |
| 199 __ slt(CMPRES1, left, right); |
| 200 } |
188 break; | 201 break; |
189 case GT: | 202 } |
190 __ mov(result, CMPRES2); | 203 case LE: |
| 204 zero_is_false = false; |
| 205 // fall through. |
| 206 case GT: { |
| 207 if (left == IMM) { |
| 208 __ slti(CMPRES1, right, Immediate(true_condition.imm())); |
| 209 } else if (right == IMM) { |
| 210 __ slti(CMPRES1, left, Immediate(true_condition.imm() + 1)); |
| 211 zero_is_false = !zero_is_false; |
| 212 } else { |
| 213 __ slt(CMPRES1, right, left); |
| 214 } |
191 break; | 215 break; |
192 case GE: | 216 } |
193 __ xori(result, CMPRES1, Immediate(1)); | 217 case UGE: |
| 218 zero_is_false = false; |
| 219 // fall through. |
| 220 case ULT: { |
| 221 ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used. |
| 222 __ sltu(CMPRES1, left, right); |
194 break; | 223 break; |
195 case LT: | 224 } |
196 __ mov(result, CMPRES1); | 225 case ULE: |
| 226 zero_is_false = false; |
| 227 // fall through. |
| 228 case UGT: { |
| 229 ASSERT((left != IMM) && (right != IMM)); // No unsigned constants used. |
| 230 __ sltu(CMPRES1, right, left); |
197 break; | 231 break; |
198 case LE: | 232 } |
199 __ xori(result, CMPRES2, Immediate(1)); | |
200 break; | |
201 default: | 233 default: |
202 UNREACHABLE(); | 234 UNREACHABLE(); |
203 break; | |
204 } | 235 } |
205 | 236 |
206 if (is_power_of_two_kind) { | 237 // CMPRES1 is the evaluated condition, zero or non-zero, as specified by the |
207 const intptr_t shift = | 238 // flag zero_is_false. |
208 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value)); | 239 Register false_value_reg; |
209 __ sll(result, result, shift + kSmiTagSize); | 240 if (false_value == 0) { |
| 241 false_value_reg = ZR; |
210 } else { | 242 } else { |
211 __ AddImmediate(result, result, -1); | 243 __ LoadImmediate(CMPRES2, Smi::RawValue(false_value)); |
212 const int32_t val = | 244 false_value_reg = CMPRES2; |
213 Smi::RawValue(true_value) - Smi::RawValue(false_value); | 245 } |
214 __ AndImmediate(result, result, val); | 246 if (zero_is_false) { |
215 if (false_value != 0) { | 247 __ movz(result, false_value_reg, CMPRES1); |
216 __ AddImmediate(result, result, Smi::RawValue(false_value)); | 248 } else { |
217 } | 249 __ movn(result, false_value_reg, CMPRES1); |
218 } | 250 } |
219 } | 251 } |
220 | 252 |
221 | 253 |
222 LocationSummary* ClosureCallInstr::MakeLocationSummary(Isolate* isolate, | 254 LocationSummary* ClosureCallInstr::MakeLocationSummary(Isolate* isolate, |
223 bool opt) const { | 255 bool opt) const { |
224 const intptr_t kNumInputs = 1; | 256 const intptr_t kNumInputs = 1; |
225 const intptr_t kNumTemps = 0; | 257 const intptr_t kNumTemps = 0; |
226 LocationSummary* summary = new(isolate) LocationSummary( | 258 LocationSummary* summary = new(isolate) LocationSummary( |
227 isolate, kNumInputs, kNumTemps, LocationSummary::kCall); | 259 isolate, kNumInputs, kNumTemps, LocationSummary::kCall); |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
485 if (value_is_smi == NULL) { | 517 if (value_is_smi == NULL) { |
486 __ beq(CMPRES1, ZR, &done); | 518 __ beq(CMPRES1, ZR, &done); |
487 } else { | 519 } else { |
488 __ beq(CMPRES1, ZR, value_is_smi); | 520 __ beq(CMPRES1, ZR, value_is_smi); |
489 } | 521 } |
490 __ LoadClassId(value_cid_reg, value_reg); | 522 __ LoadClassId(value_cid_reg, value_reg); |
491 __ Bind(&done); | 523 __ Bind(&done); |
492 } | 524 } |
493 | 525 |
494 | 526 |
495 static Condition TokenKindToSmiCondition(Token::Kind kind) { | 527 static RelationOperator TokenKindToIntRelOp(Token::Kind kind) { |
496 switch (kind) { | 528 switch (kind) { |
497 case Token::kEQ: return EQ; | 529 case Token::kEQ: return EQ; |
498 case Token::kNE: return NE; | 530 case Token::kNE: return NE; |
499 case Token::kLT: return LT; | 531 case Token::kLT: return LT; |
500 case Token::kGT: return GT; | 532 case Token::kGT: return GT; |
501 case Token::kLTE: return LE; | 533 case Token::kLTE: return LE; |
502 case Token::kGTE: return GE; | 534 case Token::kGTE: return GE; |
503 default: | 535 default: |
504 UNREACHABLE(); | 536 UNREACHABLE(); |
505 return VS; | 537 return NV; |
506 } | 538 } |
507 } | 539 } |
508 | 540 |
509 | 541 |
510 // Branches on condition c assuming comparison results in CMPRES1 and CMPRES2. | 542 static RelationOperator TokenKindToUintRelOp(Token::Kind kind) { |
511 static void EmitBranchAfterCompare( | 543 switch (kind) { |
512 FlowGraphCompiler* compiler, Condition condition, Label* is_true) { | 544 case Token::kEQ: return EQ; |
513 switch (condition) { | 545 case Token::kNE: return NE; |
514 case EQ: __ beq(CMPRES1, CMPRES2, is_true); break; | 546 case Token::kLT: return ULT; |
515 case NE: __ bne(CMPRES1, CMPRES2, is_true); break; | 547 case Token::kGT: return UGT; |
516 case GT: __ bne(CMPRES2, ZR, is_true); break; | 548 case Token::kLTE: return ULE; |
517 case GE: __ beq(CMPRES1, ZR, is_true); break; | 549 case Token::kGTE: return UGE; |
518 case LT: __ bne(CMPRES1, ZR, is_true); break; | |
519 case LE: __ beq(CMPRES2, ZR, is_true); break; | |
520 default: | 550 default: |
521 UNREACHABLE(); | 551 UNREACHABLE(); |
522 break; | 552 return NV; |
523 } | 553 } |
524 } | 554 } |
525 | 555 |
526 | 556 |
527 static Condition FlipCondition(Condition condition) { | 557 // The comparison code to emit is specified by true_condition. |
528 switch (condition) { | |
529 case EQ: return EQ; | |
530 case NE: return NE; | |
531 case LT: return GT; | |
532 case LE: return GE; | |
533 case GT: return LT; | |
534 case GE: return LE; | |
535 default: | |
536 UNREACHABLE(); | |
537 return EQ; | |
538 } | |
539 } | |
540 | |
541 | |
542 // The comparison result is in CMPRES1/CMPRES2. | |
543 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, | 558 static void EmitBranchOnCondition(FlowGraphCompiler* compiler, |
544 Condition true_condition, | 559 Condition true_condition, |
545 BranchLabels labels) { | 560 BranchLabels labels) { |
546 __ TraceSimMsg("ControlInstruction::EmitBranchOnCondition"); | 561 __ TraceSimMsg("ControlInstruction::EmitBranchOnCondition"); |
547 if (labels.fall_through == labels.false_label) { | 562 if (labels.fall_through == labels.false_label) { |
548 // If the next block is the false successor, fall through to it. | 563 // If the next block is the false successor, fall through to it. |
549 EmitBranchAfterCompare(compiler, true_condition, labels.true_label); | 564 __ BranchOnCondition(true_condition, labels.true_label); |
550 } else { | 565 } else { |
551 // If the next block is not the false successor, branch to it. | 566 // If the next block is not the false successor, branch to it. |
552 Condition false_condition = NegateCondition(true_condition); | 567 Condition false_condition = NegateCondition(true_condition); |
553 EmitBranchAfterCompare(compiler, false_condition, labels.false_label); | 568 __ BranchOnCondition(false_condition, labels.false_label); |
554 // Fall through or jump to the true successor. | 569 // Fall through or jump to the true successor. |
555 if (labels.fall_through != labels.true_label) { | 570 if (labels.fall_through != labels.true_label) { |
556 __ b(labels.true_label); | 571 __ b(labels.true_label); |
557 } | 572 } |
558 } | 573 } |
559 } | 574 } |
560 | 575 |
561 | 576 |
562 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 577 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
563 const LocationSummary& locs, | 578 const LocationSummary& locs, |
564 Token::Kind kind) { | 579 Token::Kind kind) { |
565 __ TraceSimMsg("EmitSmiComparisonOp"); | 580 __ TraceSimMsg("EmitSmiComparisonOp"); |
566 __ Comment("EmitSmiComparisonOp"); | 581 __ Comment("EmitSmiComparisonOp"); |
567 Location left = locs.in(0); | 582 const Location left = locs.in(0); |
568 Location right = locs.in(1); | 583 const Location right = locs.in(1); |
569 ASSERT(!left.IsConstant() || !right.IsConstant()); | 584 ASSERT(!left.IsConstant() || !right.IsConstant()); |
| 585 ASSERT(left.IsRegister() || left.IsConstant()); |
| 586 ASSERT(right.IsRegister() || right.IsConstant()); |
570 | 587 |
571 Condition true_condition = TokenKindToSmiCondition(kind); | 588 int16_t imm = 0; |
572 | 589 const Register left_reg = left.IsRegister() ? |
573 if (left.IsConstant()) { | 590 left.reg() : __ LoadConditionOperand(CMPRES1, left.constant(), &imm); |
574 __ CompareObject(CMPRES1, CMPRES2, right.reg(), left.constant()); | 591 const Register right_reg = right.IsRegister() ? |
575 true_condition = FlipCondition(true_condition); | 592 right.reg() : __ LoadConditionOperand(CMPRES2, right.constant(), &imm); |
576 } else if (right.IsConstant()) { | 593 return Condition(left_reg, right_reg, TokenKindToIntRelOp(kind), imm); |
577 __ CompareObject(CMPRES1, CMPRES2, left.reg(), right.constant()); | |
578 } else { | |
579 __ slt(CMPRES1, left.reg(), right.reg()); | |
580 __ slt(CMPRES2, right.reg(), left.reg()); | |
581 } | |
582 return true_condition; | |
583 } | |
584 | |
585 | |
586 static Condition TokenKindToMintCondition(Token::Kind kind) { | |
587 switch (kind) { | |
588 case Token::kEQ: return EQ; | |
589 case Token::kNE: return NE; | |
590 case Token::kLT: return LT; | |
591 case Token::kGT: return GT; | |
592 case Token::kLTE: return LE; | |
593 case Token::kGTE: return GE; | |
594 default: | |
595 UNREACHABLE(); | |
596 return VS; | |
597 } | |
598 } | 594 } |
599 | 595 |
600 | 596 |
601 static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, | 597 static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
602 const LocationSummary& locs, | 598 const LocationSummary& locs, |
603 Token::Kind kind) { | 599 Token::Kind kind, |
| 600 BranchLabels labels) { |
604 __ TraceSimMsg("EmitUnboxedMintEqualityOp"); | 601 __ TraceSimMsg("EmitUnboxedMintEqualityOp"); |
605 __ Comment("EmitUnboxedMintEqualityOp"); | 602 __ Comment("EmitUnboxedMintEqualityOp"); |
606 ASSERT(Token::IsEqualityOperator(kind)); | 603 ASSERT(Token::IsEqualityOperator(kind)); |
607 PairLocation* left_pair = locs.in(0).AsPairLocation(); | 604 PairLocation* left_pair = locs.in(0).AsPairLocation(); |
608 Register left_lo = left_pair->At(0).reg(); | 605 Register left_lo = left_pair->At(0).reg(); |
609 Register left_hi = left_pair->At(1).reg(); | 606 Register left_hi = left_pair->At(1).reg(); |
610 PairLocation* right_pair = locs.in(1).AsPairLocation(); | 607 PairLocation* right_pair = locs.in(1).AsPairLocation(); |
611 Register right_lo = right_pair->At(0).reg(); | 608 Register right_lo = right_pair->At(0).reg(); |
612 Register right_hi = right_pair->At(1).reg(); | 609 Register right_hi = right_pair->At(1).reg(); |
613 | 610 |
614 __ xor_(CMPRES1, left_lo, right_lo); | 611 if (labels.false_label == NULL) { |
615 __ xor_(CMPRES2, left_hi, right_hi); | 612 // Generate branch-free code. |
616 __ or_(CMPRES1, CMPRES1, CMPRES2); | 613 __ xor_(CMPRES1, left_lo, right_lo); |
617 __ mov(CMPRES2, ZR); | 614 __ xor_(AT, left_hi, right_hi); |
618 return TokenKindToMintCondition(kind); | 615 __ or_(CMPRES1, CMPRES1, AT); |
| 616 return Condition(CMPRES1, ZR, TokenKindToUintRelOp(kind)); |
| 617 } else { |
| 618 if (kind == Token::kEQ) { |
| 619 __ bne(left_hi, right_hi, labels.false_label); |
| 620 } else { |
| 621 ASSERT(kind == Token::kNE); |
| 622 __ bne(left_hi, right_hi, labels.true_label); |
| 623 } |
| 624 return Condition(left_lo, right_lo, TokenKindToUintRelOp(kind)); |
| 625 } |
619 } | 626 } |
620 | 627 |
621 | 628 |
622 static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, | 629 static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, |
623 const LocationSummary& locs, | 630 const LocationSummary& locs, |
624 Token::Kind kind) { | 631 Token::Kind kind, |
| 632 BranchLabels labels) { |
625 __ TraceSimMsg("EmitUnboxedMintComparisonOp"); | 633 __ TraceSimMsg("EmitUnboxedMintComparisonOp"); |
626 __ Comment("EmitUnboxedMintComparisonOp"); | 634 __ Comment("EmitUnboxedMintComparisonOp"); |
627 PairLocation* left_pair = locs.in(0).AsPairLocation(); | 635 PairLocation* left_pair = locs.in(0).AsPairLocation(); |
628 Register left_lo = left_pair->At(0).reg(); | 636 Register left_lo = left_pair->At(0).reg(); |
629 Register left_hi = left_pair->At(1).reg(); | 637 Register left_hi = left_pair->At(1).reg(); |
630 PairLocation* right_pair = locs.in(1).AsPairLocation(); | 638 PairLocation* right_pair = locs.in(1).AsPairLocation(); |
631 Register right_lo = right_pair->At(0).reg(); | 639 Register right_lo = right_pair->At(0).reg(); |
632 Register right_hi = right_pair->At(1).reg(); | 640 Register right_hi = right_pair->At(1).reg(); |
633 | 641 |
634 Label done; | 642 if (labels.false_label == NULL) { |
635 // Compare upper halves first. | 643 // Generate branch-free code (except for skipping the lower words compare). |
636 __ slt(CMPRES1, left_hi, right_hi); | 644 // Result in CMPRES1, CMPRES2, so that CMPRES1 op CMPRES2 === left op right. |
637 __ slt(CMPRES2, right_hi, left_hi); | 645 Label done; |
638 // If higher words aren't equal, skip comparing lower words. | 646 // Compare upper halves first. |
639 __ bne(CMPRES1, CMPRES2, &done); | 647 __ slt(CMPRES1, right_hi, left_hi); |
| 648 __ slt(CMPRES2, left_hi, right_hi); |
| 649 // If higher words aren't equal, skip comparing lower words. |
| 650 __ bne(CMPRES1, CMPRES2, &done); |
640 | 651 |
641 __ sltu(CMPRES1, left_lo, right_lo); | 652 __ sltu(CMPRES1, right_lo, left_lo); |
642 __ sltu(CMPRES2, right_lo, left_lo); | 653 __ sltu(CMPRES2, left_lo, right_lo); |
643 __ Bind(&done); | 654 __ Bind(&done); |
644 | 655 return Condition(CMPRES1, CMPRES2, TokenKindToUintRelOp(kind)); |
645 return TokenKindToMintCondition(kind); | 656 } else { |
646 } | 657 switch (kind) { |
647 | 658 case Token::kLT: |
648 | 659 case Token::kLTE: { |
649 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 660 __ slt(AT, left_hi, right_hi); |
650 switch (kind) { | 661 __ bne(AT, ZR, labels.true_label); |
651 case Token::kEQ: return EQ; | 662 __ delay_slot()->slt(AT, right_hi, left_hi); |
652 case Token::kNE: return NE; | 663 __ bne(AT, ZR, labels.false_label); |
653 case Token::kLT: return LT; | 664 break; |
654 case Token::kGT: return GT; | 665 } |
655 case Token::kLTE: return LE; | 666 case Token::kGT: |
656 case Token::kGTE: return GE; | 667 case Token::kGTE: { |
657 default: | 668 __ slt(AT, left_hi, right_hi); |
658 UNREACHABLE(); | 669 __ bne(AT, ZR, labels.false_label); |
659 return VS; | 670 __ delay_slot()->slt(AT, right_hi, left_hi); |
| 671 __ bne(AT, ZR, labels.true_label); |
| 672 break; |
| 673 } |
| 674 default: |
| 675 UNREACHABLE(); |
| 676 } |
| 677 return Condition(left_lo, right_lo, TokenKindToUintRelOp(kind)); |
660 } | 678 } |
661 } | 679 } |
662 | 680 |
663 | 681 |
664 static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler, | 682 static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
665 const LocationSummary& locs, | 683 const LocationSummary& locs, |
666 Token::Kind kind, | 684 Token::Kind kind, |
667 BranchLabels labels) { | 685 BranchLabels labels) { |
668 DRegister left = locs.in(0).fpu_reg(); | 686 DRegister left = locs.in(0).fpu_reg(); |
669 DRegister right = locs.in(1).fpu_reg(); | 687 DRegister right = locs.in(1).fpu_reg(); |
670 | 688 |
671 __ Comment("DoubleComparisonOp(left=%d, right=%d)", left, right); | 689 __ Comment("DoubleComparisonOp(left=%d, right=%d)", left, right); |
672 | 690 |
673 Condition true_condition = TokenKindToDoubleCondition(kind); | |
674 __ cund(left, right); | 691 __ cund(left, right); |
675 Label* nan_label = (true_condition == NE) | 692 Label* nan_label = (kind == Token::kNE) |
676 ? labels.true_label : labels.false_label; | 693 ? labels.true_label : labels.false_label; |
677 __ bc1t(nan_label); | 694 __ bc1t(nan_label); |
678 | 695 |
679 switch (true_condition) { | 696 switch (kind) { |
680 case EQ: __ ceqd(left, right); break; | 697 case Token::kEQ: __ ceqd(left, right); break; |
681 case NE: __ ceqd(left, right); break; | 698 case Token::kNE: __ ceqd(left, right); break; |
682 case LT: __ coltd(left, right); break; | 699 case Token::kLT: __ coltd(left, right); break; |
683 case LE: __ coled(left, right); break; | 700 case Token::kLTE: __ coled(left, right); break; |
684 case GT: __ coltd(right, left); break; | 701 case Token::kGT: __ coltd(right, left); break; |
685 case GE: __ coled(right, left); break; | 702 case Token::kGTE: __ coled(right, left); break; |
686 default: { | 703 default: { |
687 // We should only be passing the above conditions to this function. | 704 // We should only be passing the above conditions to this function. |
688 UNREACHABLE(); | 705 UNREACHABLE(); |
689 break; | 706 break; |
690 } | 707 } |
691 } | 708 } |
692 | 709 |
693 // Ordering is expected to be described by CMPRES1, CMPRES2. | 710 if (labels.false_label == NULL) { |
694 __ LoadImmediate(TMP, 1); | 711 // Generate branch-free code and return result in condition. |
695 if (true_condition == NE) { | 712 __ LoadImmediate(CMPRES1, 1); |
696 __ movf(CMPRES1, ZR); | 713 if (kind == Token::kNE) { |
697 __ movt(CMPRES1, TMP); | 714 __ movf(CMPRES1, ZR); |
| 715 } else { |
| 716 __ movt(CMPRES1, ZR); |
| 717 } |
| 718 return Condition(CMPRES1, ZR, EQ); |
698 } else { | 719 } else { |
699 __ movf(CMPRES1, TMP); | 720 if (labels.fall_through == labels.false_label) { |
700 __ movt(CMPRES1, ZR); | 721 if (kind == Token::kNE) { |
| 722 __ bc1f(labels.true_label); |
| 723 } else { |
| 724 __ bc1t(labels.true_label); |
| 725 } |
| 726 // Since we already branched on true, return the never true condition. |
| 727 return Condition(CMPRES1, CMPRES2, NV); |
| 728 } else { |
| 729 if (kind == Token::kNE) { |
| 730 __ bc1t(labels.false_label); |
| 731 } else { |
| 732 __ bc1f(labels.false_label); |
| 733 } |
| 734 // Since we already branched on false, return the always true condition. |
| 735 return Condition(CMPRES1, CMPRES2, AL); |
| 736 } |
701 } | 737 } |
702 __ mov(CMPRES2, ZR); | |
703 return EQ; | |
704 } | 738 } |
705 | 739 |
706 | 740 |
707 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 741 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
708 BranchLabels labels) { | 742 BranchLabels labels) { |
709 if (operation_cid() == kSmiCid) { | 743 if (operation_cid() == kSmiCid) { |
710 return EmitSmiComparisonOp(compiler, *locs(), kind()); | 744 return EmitSmiComparisonOp(compiler, *locs(), kind()); |
711 } else if (operation_cid() == kMintCid) { | 745 } else if (operation_cid() == kMintCid) { |
712 return EmitUnboxedMintEqualityOp(compiler, *locs(), kind()); | 746 return EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), labels); |
713 } else { | 747 } else { |
714 ASSERT(operation_cid() == kDoubleCid); | 748 ASSERT(operation_cid() == kDoubleCid); |
715 return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); | 749 return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); |
716 } | 750 } |
717 } | 751 } |
718 | 752 |
719 | 753 |
720 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 754 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
721 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 755 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
722 __ Comment("EqualityCompareInstr"); | 756 __ Comment("EqualityCompareInstr"); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
768 Register left = locs()->in(0).reg(); | 802 Register left = locs()->in(0).reg(); |
769 Location right = locs()->in(1); | 803 Location right = locs()->in(1); |
770 if (right.IsConstant()) { | 804 if (right.IsConstant()) { |
771 ASSERT(right.constant().IsSmi()); | 805 ASSERT(right.constant().IsSmi()); |
772 const int32_t imm = | 806 const int32_t imm = |
773 reinterpret_cast<int32_t>(right.constant().raw()); | 807 reinterpret_cast<int32_t>(right.constant().raw()); |
774 __ AndImmediate(CMPRES1, left, imm); | 808 __ AndImmediate(CMPRES1, left, imm); |
775 } else { | 809 } else { |
776 __ and_(CMPRES1, left, right.reg()); | 810 __ and_(CMPRES1, left, right.reg()); |
777 } | 811 } |
778 __ mov(CMPRES2, ZR); | 812 return Condition(CMPRES1, ZR, (kind() == Token::kNE) ? NE : EQ); |
779 Condition true_condition = (kind() == Token::kNE) ? NE : EQ; | |
780 return true_condition; | |
781 } | 813 } |
782 | 814 |
783 | 815 |
784 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 816 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
785 // Never emitted outside of the BranchInstr. | 817 // Never emitted outside of the BranchInstr. |
786 UNREACHABLE(); | 818 UNREACHABLE(); |
787 } | 819 } |
788 | 820 |
789 | 821 |
790 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 822 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
834 } | 866 } |
835 // No match found, deoptimize or false. | 867 // No match found, deoptimize or false. |
836 if (deopt == NULL) { | 868 if (deopt == NULL) { |
837 Label* target = result ? labels.false_label : labels.true_label; | 869 Label* target = result ? labels.false_label : labels.true_label; |
838 if (target != labels.fall_through) { | 870 if (target != labels.fall_through) { |
839 __ b(target); | 871 __ b(target); |
840 } | 872 } |
841 } else { | 873 } else { |
842 __ b(deopt); | 874 __ b(deopt); |
843 } | 875 } |
844 // Dummy result as the last instruction is a jump, any conditional | 876 // Dummy result as the last instruction is a jump or fall through. |
845 // branch using the result will therefore be skipped. | 877 return Condition(CMPRES1, ZR, AL); |
846 return EQ; | |
847 } | 878 } |
848 | 879 |
849 | 880 |
850 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 881 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
851 BranchInstr* branch) { | 882 BranchInstr* branch) { |
852 BranchLabels labels = compiler->CreateBranchLabels(branch); | 883 BranchLabels labels = compiler->CreateBranchLabels(branch); |
853 EmitComparisonCode(compiler, labels); | 884 EmitComparisonCode(compiler, labels); |
854 } | 885 } |
855 | 886 |
856 | 887 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
903 summary->set_out(0, Location::RequiresRegister()); | 934 summary->set_out(0, Location::RequiresRegister()); |
904 return summary; | 935 return summary; |
905 } | 936 } |
906 | 937 |
907 | 938 |
908 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 939 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
909 BranchLabels labels) { | 940 BranchLabels labels) { |
910 if (operation_cid() == kSmiCid) { | 941 if (operation_cid() == kSmiCid) { |
911 return EmitSmiComparisonOp(compiler, *locs(), kind()); | 942 return EmitSmiComparisonOp(compiler, *locs(), kind()); |
912 } else if (operation_cid() == kMintCid) { | 943 } else if (operation_cid() == kMintCid) { |
913 return EmitUnboxedMintComparisonOp(compiler, *locs(), kind()); | 944 return EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), labels); |
914 } else { | 945 } else { |
915 ASSERT(operation_cid() == kDoubleCid); | 946 ASSERT(operation_cid() == kDoubleCid); |
916 return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); | 947 return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels); |
917 } | 948 } |
918 } | 949 } |
919 | 950 |
920 | 951 |
921 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 952 void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
922 __ TraceSimMsg("RelationalOpInstr"); | 953 __ TraceSimMsg("RelationalOpInstr"); |
923 | 954 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1038 LocationSummary::kNoCall); | 1069 LocationSummary::kNoCall); |
1039 } | 1070 } |
1040 | 1071 |
1041 | 1072 |
1042 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1073 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
1043 __ TraceSimMsg("StringToCharCodeInstr"); | 1074 __ TraceSimMsg("StringToCharCodeInstr"); |
1044 | 1075 |
1045 ASSERT(cid_ == kOneByteStringCid); | 1076 ASSERT(cid_ == kOneByteStringCid); |
1046 Register str = locs()->in(0).reg(); | 1077 Register str = locs()->in(0).reg(); |
1047 Register result = locs()->out(0).reg(); | 1078 Register result = locs()->out(0).reg(); |
1048 Label done, is_one; | 1079 ASSERT(str != result); |
| 1080 Label done; |
1049 __ lw(result, FieldAddress(str, String::length_offset())); | 1081 __ lw(result, FieldAddress(str, String::length_offset())); |
1050 __ BranchEqual(result, Immediate(Smi::RawValue(1)), &is_one); | 1082 __ BranchNotEqual(result, Immediate(Smi::RawValue(1)), &done); |
1051 __ LoadImmediate(result, Smi::RawValue(-1)); | 1083 __ delay_slot()->addiu(result, ZR, Immediate(Smi::RawValue(-1))); |
1052 __ b(&done); | |
1053 __ Bind(&is_one); | |
1054 __ lbu(result, FieldAddress(str, OneByteString::data_offset())); | 1084 __ lbu(result, FieldAddress(str, OneByteString::data_offset())); |
1055 __ SmiTag(result); | 1085 __ SmiTag(result); |
1056 __ Bind(&done); | 1086 __ Bind(&done); |
1057 } | 1087 } |
1058 | 1088 |
1059 | 1089 |
1060 LocationSummary* StringInterpolateInstr::MakeLocationSummary(Isolate* isolate, | 1090 LocationSummary* StringInterpolateInstr::MakeLocationSummary(Isolate* isolate, |
1061 bool opt) const { | 1091 bool opt) const { |
1062 const intptr_t kNumInputs = 1; | 1092 const intptr_t kNumInputs = 1; |
1063 const intptr_t kNumTemps = 0; | 1093 const intptr_t kNumTemps = 0; |
(...skipping 1904 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2968 ASSERT(shift_count > 0); | 2998 ASSERT(shift_count > 0); |
2969 __ sra(result, temp, shift_count); | 2999 __ sra(result, temp, shift_count); |
2970 if (value < 0) { | 3000 if (value < 0) { |
2971 __ subu(result, ZR, result); | 3001 __ subu(result, ZR, result); |
2972 } | 3002 } |
2973 __ SmiTag(result); | 3003 __ SmiTag(result); |
2974 break; | 3004 break; |
2975 } | 3005 } |
2976 case Token::kBIT_AND: { | 3006 case Token::kBIT_AND: { |
2977 // No overflow check. | 3007 // No overflow check. |
2978 if (Utils::IsUint(kImmBits, imm)) { | 3008 __ AndImmediate(result, left, imm); |
2979 __ andi(result, left, Immediate(imm)); | |
2980 } else { | |
2981 __ LoadImmediate(TMP, imm); | |
2982 __ and_(result, left, TMP); | |
2983 } | |
2984 break; | 3009 break; |
2985 } | 3010 } |
2986 case Token::kBIT_OR: { | 3011 case Token::kBIT_OR: { |
2987 // No overflow check. | 3012 // No overflow check. |
2988 if (Utils::IsUint(kImmBits, imm)) { | 3013 __ OrImmediate(result, left, imm); |
2989 __ ori(result, left, Immediate(imm)); | |
2990 } else { | |
2991 __ LoadImmediate(TMP, imm); | |
2992 __ or_(result, left, TMP); | |
2993 } | |
2994 break; | 3014 break; |
2995 } | 3015 } |
2996 case Token::kBIT_XOR: { | 3016 case Token::kBIT_XOR: { |
2997 // No overflow check. | 3017 // No overflow check. |
2998 if (Utils::IsUint(kImmBits, imm)) { | 3018 __ XorImmediate(result, left, imm); |
2999 __ xori(result, left, Immediate(imm)); | |
3000 } else { | |
3001 __ LoadImmediate(TMP, imm); | |
3002 __ xor_(result, left, TMP); | |
3003 } | |
3004 break; | 3019 break; |
3005 } | 3020 } |
3006 case Token::kSHR: { | 3021 case Token::kSHR: { |
3007 // sarl operation masks the count to 5 bits. | 3022 // sarl operation masks the count to 5 bits. |
3008 const intptr_t kCountLimit = 0x1F; | 3023 const intptr_t kCountLimit = 0x1F; |
3009 const intptr_t value = Smi::Cast(constant).Value(); | 3024 const intptr_t value = Smi::Cast(constant).Value(); |
3010 __ TraceSimMsg("kSHR"); | 3025 __ TraceSimMsg("kSHR"); |
3011 __ sra(result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); | 3026 __ sra(result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); |
3012 __ SmiTag(result); | 3027 __ SmiTag(result); |
3013 break; | 3028 break; |
(...skipping 2555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5569 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); | 5584 compiler->GenerateCall(token_pos(), &label, stub_kind_, locs()); |
5570 #if defined(DEBUG) | 5585 #if defined(DEBUG) |
5571 __ LoadImmediate(S4, kInvalidObjectPointer); | 5586 __ LoadImmediate(S4, kInvalidObjectPointer); |
5572 __ LoadImmediate(S5, kInvalidObjectPointer); | 5587 __ LoadImmediate(S5, kInvalidObjectPointer); |
5573 #endif | 5588 #endif |
5574 } | 5589 } |
5575 | 5590 |
5576 } // namespace dart | 5591 } // namespace dart |
5577 | 5592 |
5578 #endif // defined TARGET_ARCH_MIPS | 5593 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |