| 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 |