| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 UNREACHABLE(); | 255 UNREACHABLE(); |
| 256 return OVERFLOW; | 256 return OVERFLOW; |
| 257 } | 257 } |
| 258 } | 258 } |
| 259 | 259 |
| 260 | 260 |
| 261 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { | 261 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { |
| 262 const intptr_t kNumInputs = 2; | 262 const intptr_t kNumInputs = 2; |
| 263 const bool is_checked_strict_equal = | 263 const bool is_checked_strict_equal = |
| 264 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 264 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 265 if (receiver_class_id() == kMintCid) { |
| 266 const intptr_t kNumTemps = 1; |
| 267 LocationSummary* locs = |
| 268 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 269 locs->set_in(0, Location::RequiresXmmRegister()); |
| 270 locs->set_in(1, Location::RequiresXmmRegister()); |
| 271 locs->set_temp(0, Location::RequiresRegister()); |
| 272 locs->set_out(Location::RequiresRegister()); |
| 273 return locs; |
| 274 } |
| 265 if (receiver_class_id() == kDoubleCid) { | 275 if (receiver_class_id() == kDoubleCid) { |
| 266 const intptr_t kNumTemps = 0; | 276 const intptr_t kNumTemps = 0; |
| 267 LocationSummary* locs = | 277 LocationSummary* locs = |
| 268 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 278 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 269 locs->set_in(0, Location::RequiresXmmRegister()); | 279 locs->set_in(0, Location::RequiresXmmRegister()); |
| 270 locs->set_in(1, Location::RequiresXmmRegister()); | 280 locs->set_in(1, Location::RequiresXmmRegister()); |
| 271 locs->set_out(Location::RequiresRegister()); | 281 locs->set_out(Location::RequiresRegister()); |
| 272 return locs; | 282 return locs; |
| 273 } | 283 } |
| 274 if (receiver_class_id() == kSmiCid) { | 284 if (receiver_class_id() == kSmiCid) { |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 __ j(true_condition, &is_true); | 622 __ j(true_condition, &is_true); |
| 613 __ LoadObject(result, compiler->bool_false()); | 623 __ LoadObject(result, compiler->bool_false()); |
| 614 __ jmp(&done); | 624 __ jmp(&done); |
| 615 __ Bind(&is_true); | 625 __ Bind(&is_true); |
| 616 __ LoadObject(result, compiler->bool_true()); | 626 __ LoadObject(result, compiler->bool_true()); |
| 617 __ Bind(&done); | 627 __ Bind(&done); |
| 618 } | 628 } |
| 619 } | 629 } |
| 620 | 630 |
| 621 | 631 |
| 632 static Condition TokenKindToMintCondition(Token::Kind kind) { |
| 633 switch (kind) { |
| 634 case Token::kEQ: return EQUAL; |
| 635 case Token::kNE: return NOT_EQUAL; |
| 636 default: |
| 637 UNIMPLEMENTED(); |
| 638 return OVERFLOW; |
| 639 } |
| 640 } |
| 641 |
| 642 |
| 643 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
| 644 const LocationSummary& locs, |
| 645 Token::Kind kind, |
| 646 BranchInstr* branch) { |
| 647 ASSERT(Token::IsEqualityOperator(kind)); |
| 648 XmmRegister left = locs.in(0).xmm_reg(); |
| 649 XmmRegister right = locs.in(1).xmm_reg(); |
| 650 Register temp = locs.temp(0).reg(); |
| 651 __ movaps(XMM0, left); |
| 652 __ pcmpeqq(XMM0, right); |
| 653 __ movd(temp, XMM0); |
| 654 |
| 655 Condition true_condition = TokenKindToMintCondition(kind); |
| 656 __ cmpl(temp, Immediate(-1)); |
| 657 |
| 658 if (branch != NULL) { |
| 659 branch->EmitBranchOnCondition(compiler, true_condition); |
| 660 } else { |
| 661 Register result = locs.out().reg(); |
| 662 Label done, is_true; |
| 663 __ j(true_condition, &is_true); |
| 664 __ LoadObject(result, compiler->bool_false()); |
| 665 __ jmp(&done); |
| 666 __ Bind(&is_true); |
| 667 __ LoadObject(result, compiler->bool_true()); |
| 668 __ Bind(&done); |
| 669 } |
| 670 } |
| 671 |
| 672 |
| 622 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 673 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| 623 switch (kind) { | 674 switch (kind) { |
| 624 case Token::kEQ: return EQUAL; | 675 case Token::kEQ: return EQUAL; |
| 625 case Token::kNE: return NOT_EQUAL; | 676 case Token::kNE: return NOT_EQUAL; |
| 626 case Token::kLT: return BELOW; | 677 case Token::kLT: return BELOW; |
| 627 case Token::kGT: return ABOVE; | 678 case Token::kGT: return ABOVE; |
| 628 case Token::kLTE: return BELOW_EQUAL; | 679 case Token::kLTE: return BELOW_EQUAL; |
| 629 case Token::kGTE: return ABOVE_EQUAL; | 680 case Token::kGTE: return ABOVE_EQUAL; |
| 630 default: | 681 default: |
| 631 UNREACHABLE(); | 682 UNREACHABLE(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 653 | 704 |
| 654 | 705 |
| 655 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 706 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 656 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 707 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 657 BranchInstr* kNoBranch = NULL; | 708 BranchInstr* kNoBranch = NULL; |
| 658 if (receiver_class_id() == kSmiCid) { | 709 if (receiver_class_id() == kSmiCid) { |
| 659 // Deoptimizes if both arguments not Smi. | 710 // Deoptimizes if both arguments not Smi. |
| 660 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch); | 711 EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch); |
| 661 return; | 712 return; |
| 662 } | 713 } |
| 714 if (receiver_class_id() == kMintCid) { |
| 715 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); |
| 716 return; |
| 717 } |
| 663 if (receiver_class_id() == kDoubleCid) { | 718 if (receiver_class_id() == kDoubleCid) { |
| 664 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); | 719 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); |
| 665 return; | 720 return; |
| 666 } | 721 } |
| 667 const bool is_checked_strict_equal = | 722 const bool is_checked_strict_equal = |
| 668 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 723 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 669 if (is_checked_strict_equal) { | 724 if (is_checked_strict_equal) { |
| 670 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch, | 725 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch, |
| 671 deopt_id()); | 726 deopt_id()); |
| 672 return; | 727 return; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 686 | 741 |
| 687 | 742 |
| 688 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 743 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 689 BranchInstr* branch) { | 744 BranchInstr* branch) { |
| 690 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 745 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 691 if (receiver_class_id() == kSmiCid) { | 746 if (receiver_class_id() == kSmiCid) { |
| 692 // Deoptimizes if both arguments not Smi. | 747 // Deoptimizes if both arguments not Smi. |
| 693 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); | 748 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); |
| 694 return; | 749 return; |
| 695 } | 750 } |
| 751 if (receiver_class_id() == kMintCid) { |
| 752 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); |
| 753 return; |
| 754 } |
| 696 if (receiver_class_id() == kDoubleCid) { | 755 if (receiver_class_id() == kDoubleCid) { |
| 697 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); | 756 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); |
| 698 return; | 757 return; |
| 699 } | 758 } |
| 700 const bool is_checked_strict_equal = | 759 const bool is_checked_strict_equal = |
| 701 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 760 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 702 if (is_checked_strict_equal) { | 761 if (is_checked_strict_equal) { |
| 703 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch, | 762 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch, |
| 704 deopt_id()); | 763 deopt_id()); |
| 705 return; | 764 return; |
| (...skipping 1512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2218 __ j(ABOVE_EQUAL, deopt); | 2277 __ j(ABOVE_EQUAL, deopt); |
| 2219 } else { | 2278 } else { |
| 2220 Register receiver = locs()->in(0).reg(); | 2279 Register receiver = locs()->in(0).reg(); |
| 2221 Register index = locs()->in(1).reg(); | 2280 Register index = locs()->in(1).reg(); |
| 2222 __ cmpl(index, FieldAddress(receiver, length_offset)); | 2281 __ cmpl(index, FieldAddress(receiver, length_offset)); |
| 2223 __ j(ABOVE_EQUAL, deopt); | 2282 __ j(ABOVE_EQUAL, deopt); |
| 2224 } | 2283 } |
| 2225 } | 2284 } |
| 2226 | 2285 |
| 2227 | 2286 |
| 2287 LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const { |
| 2288 const intptr_t kNumInputs = 1; |
| 2289 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; |
| 2290 LocationSummary* summary = |
| 2291 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2292 summary->set_in(0, Location::RequiresRegister()); |
| 2293 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); |
| 2294 summary->set_out(Location::RequiresXmmRegister()); |
| 2295 return summary; |
| 2296 } |
| 2297 |
| 2298 |
| 2299 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2300 const intptr_t value_cid = value()->ResultCid(); |
| 2301 const Register value = locs()->in(0).reg(); |
| 2302 const XmmRegister result = locs()->out().xmm_reg(); |
| 2303 |
| 2304 if (value_cid == kMintCid) { |
| 2305 __ movsd(result, FieldAddress(value, Mint::value_offset())); |
| 2306 } else if (value_cid == kSmiCid) { |
| 2307 __ SmiUntag(value); // Untag input before conversion. |
| 2308 __ movd(result, value); |
| 2309 __ pmovsxdq(result, result); |
| 2310 __ SmiTag(value); // Restore input register. |
| 2311 } else { |
| 2312 Register temp = locs()->temp(0).reg(); |
| 2313 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp); |
| 2314 Label is_smi, done; |
| 2315 __ testl(value, Immediate(kSmiTagMask)); |
| 2316 __ j(ZERO, &is_smi); |
| 2317 __ CompareClassId(value, kMintCid, temp); |
| 2318 __ j(NOT_EQUAL, deopt); |
| 2319 __ movsd(result, FieldAddress(value, Mint::value_offset())); |
| 2320 __ jmp(&done); |
| 2321 __ Bind(&is_smi); |
| 2322 __ movl(temp, value); |
| 2323 __ SmiUntag(temp); |
| 2324 __ movd(result, temp); |
| 2325 __ pmovsxdq(result, result); |
| 2326 __ Bind(&done); |
| 2327 } |
| 2328 } |
| 2329 |
| 2330 |
| 2331 LocationSummary* BoxIntegerInstr::MakeLocationSummary() const { |
| 2332 const intptr_t kNumInputs = 1; |
| 2333 const intptr_t kNumTemps = 2; |
| 2334 LocationSummary* summary = |
| 2335 new LocationSummary(kNumInputs, |
| 2336 kNumTemps, |
| 2337 LocationSummary::kCallOnSlowPath); |
| 2338 summary->set_in(0, Location::RequiresXmmRegister()); |
| 2339 summary->set_temp(0, Location::RegisterLocation(EAX)); |
| 2340 summary->set_temp(1, Location::RegisterLocation(EDX)); |
| 2341 // TODO(fschneider): Save one temp by using result register as a temp. |
| 2342 summary->set_out(Location::RequiresRegister()); |
| 2343 return summary; |
| 2344 } |
| 2345 |
| 2346 |
| 2347 class BoxIntegerSlowPath : public SlowPathCode { |
| 2348 public: |
| 2349 explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) |
| 2350 : instruction_(instruction) { } |
| 2351 |
| 2352 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2353 __ Bind(entry_label()); |
| 2354 const Class& mint_class = |
| 2355 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()); |
| 2356 const Code& stub = |
| 2357 Code::Handle(StubCode::GetAllocationStubForClass(mint_class)); |
| 2358 const ExternalLabel label(mint_class.ToCString(), stub.EntryPoint()); |
| 2359 |
| 2360 LocationSummary* locs = instruction_->locs(); |
| 2361 locs->live_registers()->Remove(locs->out()); |
| 2362 |
| 2363 compiler->SaveLiveRegisters(locs); |
| 2364 compiler->GenerateCall(0, // No token pos. |
| 2365 &label, |
| 2366 PcDescriptors::kOther, |
| 2367 locs); |
| 2368 if (EAX != locs->out().reg()) __ movl(locs->out().reg(), EAX); |
| 2369 compiler->RestoreLiveRegisters(locs); |
| 2370 |
| 2371 __ jmp(exit_label()); |
| 2372 } |
| 2373 |
| 2374 private: |
| 2375 BoxIntegerInstr* instruction_; |
| 2376 }; |
| 2377 |
| 2378 |
| 2379 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2380 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| 2381 compiler->AddSlowPathCode(slow_path); |
| 2382 |
| 2383 Register out_reg = locs()->out().reg(); |
| 2384 XmmRegister value = locs()->in(0).xmm_reg(); |
| 2385 |
| 2386 // Unboxed operations produce smis or mint-sized values. |
| 2387 // Check if value fits into a smi. |
| 2388 Label not_smi, done; |
| 2389 __ pextrd(EDX, value, Immediate(1)); // Upper half. |
| 2390 __ pextrd(EAX, value, Immediate(0)); // Lower half. |
| 2391 // 1. Compute (x + -kMinSmi) which has to be in the range |
| 2392 // 0 .. -kMinSmi+kMaxSmi for x to fit into a smi. |
| 2393 __ addl(EAX, Immediate(0x40000000)); |
| 2394 __ adcl(EDX, Immediate(0)); |
| 2395 // 2. Unsigned compare to -kMinSmi+kMaxSmi. |
| 2396 __ cmpl(EAX, Immediate(0x80000000)); |
| 2397 __ sbbl(EDX, Immediate(0)); |
| 2398 __ j(ABOVE_EQUAL, ¬_smi); |
| 2399 // 3. Restore lower half if result is a smi. |
| 2400 __ subl(EAX, Immediate(0x40000000)); |
| 2401 |
| 2402 __ SmiTag(EAX); |
| 2403 __ movl(out_reg, EAX); |
| 2404 __ jmp(&done); |
| 2405 |
| 2406 __ Bind(¬_smi); |
| 2407 AssemblerMacros::TryAllocate( |
| 2408 compiler->assembler(), |
| 2409 Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), |
| 2410 slow_path->entry_label(), |
| 2411 Assembler::kFarJump, |
| 2412 out_reg); |
| 2413 __ Bind(slow_path->exit_label()); |
| 2414 __ movsd(FieldAddress(out_reg, Mint::value_offset()), value); |
| 2415 __ Bind(&done); |
| 2416 } |
| 2417 |
| 2418 |
| 2419 LocationSummary* UnboxedMintBinaryOpInstr::MakeLocationSummary() const { |
| 2420 const intptr_t kNumInputs = 2; |
| 2421 const intptr_t kNumTemps = 0; |
| 2422 LocationSummary* summary = |
| 2423 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2424 summary->set_in(0, Location::RequiresXmmRegister()); |
| 2425 summary->set_in(1, Location::RequiresXmmRegister()); |
| 2426 summary->set_out(Location::SameAsFirstInput()); |
| 2427 return summary; |
| 2428 } |
| 2429 |
| 2430 |
| 2431 void UnboxedMintBinaryOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2432 XmmRegister left = locs()->in(0).xmm_reg(); |
| 2433 XmmRegister right = locs()->in(1).xmm_reg(); |
| 2434 |
| 2435 ASSERT(locs()->out().xmm_reg() == left); |
| 2436 |
| 2437 switch (op_kind()) { |
| 2438 case Token::kBIT_AND: __ andpd(left, right); break; |
| 2439 case Token::kBIT_OR: __ orpd(left, right); break; |
| 2440 case Token::kBIT_XOR: __ xorpd(left, right); break; |
| 2441 default: UNREACHABLE(); |
| 2442 } |
| 2443 } |
| 2444 |
| 2445 |
| 2446 |
| 2228 } // namespace dart | 2447 } // namespace dart |
| 2229 | 2448 |
| 2230 #undef __ | 2449 #undef __ |
| 2231 | 2450 |
| 2232 #endif // defined TARGET_ARCH_X64 | 2451 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |