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

Side by Side Diff: src/ia32/lithium-codegen-ia32.cc

Issue 13426006: Improvements for x87 stack handling (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review updates Created 7 years, 8 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
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 changed_value->id(), changed_value->Mnemonic(), 359 changed_value->id(), changed_value->Mnemonic(),
360 use_id, use_mnemo); 360 use_id, use_mnemo);
361 } else { 361 } else {
362 Comment(";;; @%d: %s. <#%d>", current_instruction_, 362 Comment(";;; @%d: %s. <#%d>", current_instruction_,
363 instr->Mnemonic(), hydrogen->id()); 363 instr->Mnemonic(), hydrogen->id());
364 } 364 }
365 } else { 365 } else {
366 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); 366 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
367 } 367 }
368 } 368 }
369
370 if (!CpuFeatures::IsSupported(SSE2)) {
danno 2013/04/09 07:37:07 nit: How about putting the following 7 lines in a
mvstanton 2013/04/09 08:49:13 Done.
371 if (x87_stack_depth_ > 0) {
372 if ((instr->ClobbersDoubleRegisters() ||
373 instr->HasDoubleRegisterResult()) &&
374 !instr->HasDoubleRegisterInput()) {
375 PopX87();
376 }
377 }
378 }
379
369 instr->CompileToNative(this); 380 instr->CompileToNative(this);
381
382 if (!CpuFeatures::IsSupported(SSE2)) {
383 ASSERT(!instr->HasDoubleRegisterResult() || x87_stack_depth_ == 1);
384
385 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
386 // Make sure the floating point stack is either empty or has one item,
danno 2013/04/09 07:37:07 This code might be useful elsewhere. How about put
mvstanton 2013/04/09 08:49:13 Done with a variant: I also check if the stack has
387 // the result value of the instruction.
388 int tos = (x87_stack_depth_ > 0) ? 7 : 0;
389 const int kTopMask = 0x3800;
390 __ push(eax);
391 __ fwait();
392 __ fnstsw_ax();
393 __ and_(eax, kTopMask);
394 __ shr(eax, 11);
395 __ cmp(eax, Immediate(tos));
396 Label all_ok;
397 __ j(equal, &all_ok);
398 __ Check(equal, "FPU Top is not zero after instruction");
399 __ bind(&all_ok);
400 __ fnclex();
401 __ pop(eax);
402 }
403 }
370 } 404 }
371 } 405 }
372 EnsureSpaceForLazyDeopt(); 406 EnsureSpaceForLazyDeopt();
373 return !is_aborted(); 407 return !is_aborted();
374 } 408 }
375 409
376 410
377 bool LCodeGen::GenerateJumpTable() { 411 bool LCodeGen::GenerateJumpTable() {
378 Label needs_frame_not_call; 412 Label needs_frame_not_call;
379 Label needs_frame_is_call; 413 Label needs_frame_is_call;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 XMMRegister LCodeGen::ToDoubleRegister(int index) const { 548 XMMRegister LCodeGen::ToDoubleRegister(int index) const {
515 return XMMRegister::FromAllocationIndex(index); 549 return XMMRegister::FromAllocationIndex(index);
516 } 550 }
517 551
518 552
519 bool LCodeGen::IsX87TopOfStack(LOperand* op) const { 553 bool LCodeGen::IsX87TopOfStack(LOperand* op) const {
520 return op->IsDoubleRegister(); 554 return op->IsDoubleRegister();
521 } 555 }
522 556
523 557
558 void LCodeGen::ReadX87Operand(Operand dst) {
559 ASSERT(x87_stack_depth_ == 1);
560 __ fst_d(dst);
561 }
562
563
564 void LCodeGen::PushX87DoubleOperand(Operand src) {
565 ASSERT(x87_stack_depth_ == 0);
566 x87_stack_depth_++;
567 __ fld_d(src);
568 }
569
570
571 void LCodeGen::PushX87FloatOperand(Operand src) {
572 ASSERT(x87_stack_depth_ == 0);
573 x87_stack_depth_++;
574 __ fld_s(src);
575 }
576
577
578 void LCodeGen::PopX87() {
579 ASSERT(x87_stack_depth_ == 1);
580 x87_stack_depth_--;
581 __ fstp(0);
582 }
583
584
585 void LCodeGen::CurrentInstructionReturnsX87Result() {
586 ASSERT(x87_stack_depth_ <= 1);
587 if (x87_stack_depth_ == 0) {
588 x87_stack_depth_ = 1;
589 }
590 }
591
524 Register LCodeGen::ToRegister(LOperand* op) const { 592 Register LCodeGen::ToRegister(LOperand* op) const {
525 ASSERT(op->IsRegister()); 593 ASSERT(op->IsRegister());
526 return ToRegister(op->index()); 594 return ToRegister(op->index());
527 } 595 }
528 596
529 597
530 XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const { 598 XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
531 ASSERT(op->IsDoubleRegister()); 599 ASSERT(op->IsDoubleRegister());
532 return ToDoubleRegister(op->index()); 600 return ToDoubleRegister(op->index());
533 } 601 }
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 translation.index(), 907 translation.index(),
840 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); 908 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
841 deoptimizations_.Add(environment, zone()); 909 deoptimizations_.Add(environment, zone());
842 } 910 }
843 } 911 }
844 912
845 913
846 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { 914 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
847 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 915 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
848 ASSERT(environment->HasBeenRegistered()); 916 ASSERT(environment->HasBeenRegistered());
917 // It's an error to deoptimize with the x87 fp stack in use.
918 ASSERT(x87_stack_depth_ == 0);
849 int id = environment->deoptimization_index(); 919 int id = environment->deoptimization_index();
850 ASSERT(info()->IsOptimizing() || info()->IsStub()); 920 ASSERT(info()->IsOptimizing() || info()->IsStub());
851 Deoptimizer::BailoutType bailout_type = info()->IsStub() 921 Deoptimizer::BailoutType bailout_type = info()->IsStub()
852 ? Deoptimizer::LAZY 922 ? Deoptimizer::LAZY
853 : Deoptimizer::EAGER; 923 : Deoptimizer::EAGER;
854 Address entry = 924 Address entry =
855 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); 925 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
856 if (entry == NULL) { 926 if (entry == NULL) {
857 Abort("bailout was not prepared"); 927 Abort("bailout was not prepared");
858 return; 928 return;
(...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after
1682 } 1752 }
1683 1753
1684 1754
1685 void LCodeGen::DoConstantI(LConstantI* instr) { 1755 void LCodeGen::DoConstantI(LConstantI* instr) {
1686 ASSERT(instr->result()->IsRegister()); 1756 ASSERT(instr->result()->IsRegister());
1687 __ Set(ToRegister(instr->result()), Immediate(instr->value())); 1757 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
1688 } 1758 }
1689 1759
1690 1760
1691 void LCodeGen::DoConstantD(LConstantD* instr) { 1761 void LCodeGen::DoConstantD(LConstantD* instr) {
1692 ASSERT(instr->result()->IsDoubleRegister());
1693 XMMRegister res = ToDoubleRegister(instr->result());
1694 double v = instr->value(); 1762 double v = instr->value();
1695 // Use xor to produce +0.0 in a fast and compact way, but avoid to 1763 uint64_t int_val = BitCast<uint64_t, double>(v);
1696 // do so if the constant is -0.0. 1764 int32_t lower = static_cast<int32_t>(int_val);
1697 if (BitCast<uint64_t, double>(v) == 0) { 1765 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
1698 __ xorps(res, res); 1766
1767 if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
1768 __ push(Immediate(lower));
1769 __ push(Immediate(upper));
1770 PushX87DoubleOperand(Operand(esp, 0));
1771 __ add(Operand(esp), Immediate(kDoubleSize));
1772 CurrentInstructionReturnsX87Result();
1699 } else { 1773 } else {
1700 Register temp = ToRegister(instr->temp()); 1774 CpuFeatureScope scope1(masm(), SSE2);
1701 uint64_t int_val = BitCast<uint64_t, double>(v); 1775 ASSERT(instr->result()->IsDoubleRegister());
1702 int32_t lower = static_cast<int32_t>(int_val); 1776 XMMRegister res = ToDoubleRegister(instr->result());
1703 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); 1777 if (int_val == 0) {
1704 if (CpuFeatures::IsSupported(SSE4_1)) { 1778 __ xorps(res, res);
1705 CpuFeatureScope scope1(masm(), SSE2); 1779 } else {
1706 CpuFeatureScope scope2(masm(), SSE4_1); 1780 Register temp = ToRegister(instr->temp());
1707 if (lower != 0) { 1781 if (CpuFeatures::IsSupported(SSE4_1)) {
1708 __ Set(temp, Immediate(lower)); 1782 CpuFeatureScope scope2(masm(), SSE4_1);
1783 if (lower != 0) {
1784 __ Set(temp, Immediate(lower));
1785 __ movd(res, Operand(temp));
1786 __ Set(temp, Immediate(upper));
1787 __ pinsrd(res, Operand(temp), 1);
1788 } else {
1789 __ xorps(res, res);
1790 __ Set(temp, Immediate(upper));
1791 __ pinsrd(res, Operand(temp), 1);
1792 }
1793 } else {
1794 __ Set(temp, Immediate(upper));
1709 __ movd(res, Operand(temp)); 1795 __ movd(res, Operand(temp));
1710 __ Set(temp, Immediate(upper)); 1796 __ psllq(res, 32);
1711 __ pinsrd(res, Operand(temp), 1); 1797 if (lower != 0) {
1712 } else { 1798 __ Set(temp, Immediate(lower));
1713 __ xorps(res, res); 1799 __ movd(xmm0, Operand(temp));
1714 __ Set(temp, Immediate(upper)); 1800 __ por(res, xmm0);
1715 __ pinsrd(res, Operand(temp), 1); 1801 }
1716 }
1717 } else {
1718 CpuFeatureScope scope(masm(), SSE2);
1719 __ Set(temp, Immediate(upper));
1720 __ movd(res, Operand(temp));
1721 __ psllq(res, 32);
1722 if (lower != 0) {
1723 __ Set(temp, Immediate(lower));
1724 __ movd(xmm0, Operand(temp));
1725 __ por(res, xmm0);
1726 } 1802 }
1727 } 1803 }
1728 } 1804 }
1729 } 1805 }
1730 1806
1731 1807
1732 void LCodeGen::DoConstantT(LConstantT* instr) { 1808 void LCodeGen::DoConstantT(LConstantT* instr) {
1733 Register reg = ToRegister(instr->result()); 1809 Register reg = ToRegister(instr->result());
1734 Handle<Object> handle = instr->value(); 1810 Handle<Object> handle = instr->value();
1735 if (handle->IsHeapObject()) { 1811 if (handle->IsHeapObject()) {
(...skipping 1415 matching lines...) Expand 10 before | Expand all | Expand 10 after
3151 elements_kind, 3227 elements_kind,
3152 0, 3228 0,
3153 instr->additional_index())); 3229 instr->additional_index()));
3154 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { 3230 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3155 if (CpuFeatures::IsSupported(SSE2)) { 3231 if (CpuFeatures::IsSupported(SSE2)) {
3156 CpuFeatureScope scope(masm(), SSE2); 3232 CpuFeatureScope scope(masm(), SSE2);
3157 XMMRegister result(ToDoubleRegister(instr->result())); 3233 XMMRegister result(ToDoubleRegister(instr->result()));
3158 __ movss(result, operand); 3234 __ movss(result, operand);
3159 __ cvtss2sd(result, result); 3235 __ cvtss2sd(result, result);
3160 } else { 3236 } else {
3161 __ fld_s(operand); 3237 PushX87FloatOperand(operand);
3162 HandleX87FPReturnValue(instr); 3238 CurrentInstructionReturnsX87Result();
3163 } 3239 }
3164 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 3240 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3165 if (CpuFeatures::IsSupported(SSE2)) { 3241 if (CpuFeatures::IsSupported(SSE2)) {
3166 CpuFeatureScope scope(masm(), SSE2); 3242 CpuFeatureScope scope(masm(), SSE2);
3167 __ movdbl(ToDoubleRegister(instr->result()), operand); 3243 __ movdbl(ToDoubleRegister(instr->result()), operand);
3168 } else { 3244 } else {
3169 __ fld_d(operand); 3245 PushX87DoubleOperand(operand);
3170 HandleX87FPReturnValue(instr); 3246 CurrentInstructionReturnsX87Result();
3171 } 3247 }
3172 } else { 3248 } else {
3173 Register result(ToRegister(instr->result())); 3249 Register result(ToRegister(instr->result()));
3174 switch (elements_kind) { 3250 switch (elements_kind) {
3175 case EXTERNAL_BYTE_ELEMENTS: 3251 case EXTERNAL_BYTE_ELEMENTS:
3176 __ movsx_b(result, operand); 3252 __ movsx_b(result, operand);
3177 break; 3253 break;
3178 case EXTERNAL_PIXEL_ELEMENTS: 3254 case EXTERNAL_PIXEL_ELEMENTS:
3179 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 3255 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3180 __ movzx_b(result, operand); 3256 __ movzx_b(result, operand);
(...skipping 24 matching lines...) Expand all
3205 case FAST_HOLEY_DOUBLE_ELEMENTS: 3281 case FAST_HOLEY_DOUBLE_ELEMENTS:
3206 case DICTIONARY_ELEMENTS: 3282 case DICTIONARY_ELEMENTS:
3207 case NON_STRICT_ARGUMENTS_ELEMENTS: 3283 case NON_STRICT_ARGUMENTS_ELEMENTS:
3208 UNREACHABLE(); 3284 UNREACHABLE();
3209 break; 3285 break;
3210 } 3286 }
3211 } 3287 }
3212 } 3288 }
3213 3289
3214 3290
3215 void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) {
3216 if (IsX87TopOfStack(instr->result())) {
3217 // Return value is already on stack. If the value has no uses, then
3218 // pop it off the FP stack. Otherwise, make sure that there are enough
3219 // copies of the value on the stack to feed all of the usages, e.g.
3220 // when the following instruction uses the return value in multiple
3221 // inputs.
3222 int count = instr->hydrogen_value()->UseCount();
3223 if (count == 0) {
3224 __ fstp(0);
3225 } else {
3226 count--;
3227 ASSERT(count <= 7);
3228 while (count-- > 0) {
3229 __ fld(0);
3230 }
3231 }
3232 } else {
3233 __ fstp_d(ToOperand(instr->result()));
3234 }
3235 }
3236
3237
3238 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { 3291 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3239 if (instr->hydrogen()->RequiresHoleCheck()) { 3292 if (instr->hydrogen()->RequiresHoleCheck()) {
3240 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + 3293 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3241 sizeof(kHoleNanLower32); 3294 sizeof(kHoleNanLower32);
3242 Operand hole_check_operand = BuildFastArrayOperand( 3295 Operand hole_check_operand = BuildFastArrayOperand(
3243 instr->elements(), instr->key(), 3296 instr->elements(), instr->key(),
3244 instr->hydrogen()->key()->representation(), 3297 instr->hydrogen()->key()->representation(),
3245 FAST_DOUBLE_ELEMENTS, 3298 FAST_DOUBLE_ELEMENTS,
3246 offset, 3299 offset,
3247 instr->additional_index()); 3300 instr->additional_index());
3248 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32)); 3301 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3249 DeoptimizeIf(equal, instr->environment()); 3302 DeoptimizeIf(equal, instr->environment());
3250 } 3303 }
3251 3304
3252 Operand double_load_operand = BuildFastArrayOperand( 3305 Operand double_load_operand = BuildFastArrayOperand(
3253 instr->elements(), 3306 instr->elements(),
3254 instr->key(), 3307 instr->key(),
3255 instr->hydrogen()->key()->representation(), 3308 instr->hydrogen()->key()->representation(),
3256 FAST_DOUBLE_ELEMENTS, 3309 FAST_DOUBLE_ELEMENTS,
3257 FixedDoubleArray::kHeaderSize - kHeapObjectTag, 3310 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3258 instr->additional_index()); 3311 instr->additional_index());
3259 if (CpuFeatures::IsSupported(SSE2)) { 3312 if (CpuFeatures::IsSupported(SSE2)) {
3260 CpuFeatureScope scope(masm(), SSE2); 3313 CpuFeatureScope scope(masm(), SSE2);
3261 XMMRegister result = ToDoubleRegister(instr->result()); 3314 XMMRegister result = ToDoubleRegister(instr->result());
3262 __ movdbl(result, double_load_operand); 3315 __ movdbl(result, double_load_operand);
3263 } else { 3316 } else {
3264 __ fld_d(double_load_operand); 3317 PushX87DoubleOperand(double_load_operand);
3265 HandleX87FPReturnValue(instr); 3318 CurrentInstructionReturnsX87Result();
3266 } 3319 }
3267 } 3320 }
3268 3321
3269 3322
3270 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { 3323 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3271 Register result = ToRegister(instr->result()); 3324 Register result = ToRegister(instr->result());
3272 3325
3273 // Load the result. 3326 // Load the result.
3274 __ mov(result, 3327 __ mov(result,
3275 BuildFastArrayOperand(instr->elements(), 3328 BuildFastArrayOperand(instr->elements(),
(...skipping 1028 matching lines...) Expand 10 before | Expand all | Expand 10 after
4304 __ SmiUntag(ToRegister(key)); 4357 __ SmiUntag(ToRegister(key));
4305 } 4358 }
4306 Operand operand(BuildFastArrayOperand( 4359 Operand operand(BuildFastArrayOperand(
4307 instr->elements(), 4360 instr->elements(),
4308 key, 4361 key,
4309 instr->hydrogen()->key()->representation(), 4362 instr->hydrogen()->key()->representation(),
4310 elements_kind, 4363 elements_kind,
4311 0, 4364 0,
4312 instr->additional_index())); 4365 instr->additional_index()));
4313 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { 4366 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
4314 CpuFeatureScope scope(masm(), SSE2); 4367 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4315 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value())); 4368 CpuFeatureScope scope(masm(), SSE2);
4316 __ movss(operand, xmm0); 4369 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
4370 __ movss(operand, xmm0);
4371 } else {
4372 __ fld(0);
4373 __ fstp_s(operand);
4374 }
4317 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 4375 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
4318 CpuFeatureScope scope(masm(), SSE2); 4376 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4319 __ movdbl(operand, ToDoubleRegister(instr->value())); 4377 CpuFeatureScope scope(masm(), SSE2);
4378 __ movdbl(operand, ToDoubleRegister(instr->value()));
4379 } else {
4380 __ fst_d(operand);
4381 }
4320 } else { 4382 } else {
4321 Register value = ToRegister(instr->value()); 4383 Register value = ToRegister(instr->value());
4322 switch (elements_kind) { 4384 switch (elements_kind) {
4323 case EXTERNAL_PIXEL_ELEMENTS: 4385 case EXTERNAL_PIXEL_ELEMENTS:
4324 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 4386 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4325 case EXTERNAL_BYTE_ELEMENTS: 4387 case EXTERNAL_BYTE_ELEMENTS:
4326 __ mov_b(operand, value); 4388 __ mov_b(operand, value);
4327 break; 4389 break;
4328 case EXTERNAL_SHORT_ELEMENTS: 4390 case EXTERNAL_SHORT_ELEMENTS:
4329 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 4391 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
(...skipping 14 matching lines...) Expand all
4344 case DICTIONARY_ELEMENTS: 4406 case DICTIONARY_ELEMENTS:
4345 case NON_STRICT_ARGUMENTS_ELEMENTS: 4407 case NON_STRICT_ARGUMENTS_ELEMENTS:
4346 UNREACHABLE(); 4408 UNREACHABLE();
4347 break; 4409 break;
4348 } 4410 }
4349 } 4411 }
4350 } 4412 }
4351 4413
4352 4414
4353 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { 4415 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4354 CpuFeatureScope scope(masm(), SSE2); 4416 ExternalReference canonical_nan_reference =
4355 XMMRegister value = ToDoubleRegister(instr->value()); 4417 ExternalReference::address_of_canonical_non_hole_nan();
4356
4357 if (instr->NeedsCanonicalization()) {
4358 Label have_value;
4359
4360 __ ucomisd(value, value);
4361 __ j(parity_odd, &have_value); // NaN.
4362
4363 ExternalReference canonical_nan_reference =
4364 ExternalReference::address_of_canonical_non_hole_nan();
4365 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4366 __ bind(&have_value);
4367 }
4368
4369 Operand double_store_operand = BuildFastArrayOperand( 4418 Operand double_store_operand = BuildFastArrayOperand(
4370 instr->elements(), 4419 instr->elements(),
4371 instr->key(), 4420 instr->key(),
4372 instr->hydrogen()->key()->representation(), 4421 instr->hydrogen()->key()->representation(),
4373 FAST_DOUBLE_ELEMENTS, 4422 FAST_DOUBLE_ELEMENTS,
4374 FixedDoubleArray::kHeaderSize - kHeapObjectTag, 4423 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4375 instr->additional_index()); 4424 instr->additional_index());
4376 __ movdbl(double_store_operand, value); 4425
4426 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4427 CpuFeatureScope scope(masm(), SSE2);
4428 XMMRegister value = ToDoubleRegister(instr->value());
4429
4430 if (instr->NeedsCanonicalization()) {
4431 Label have_value;
4432
4433 __ ucomisd(value, value);
4434 __ j(parity_odd, &have_value); // NaN.
4435
4436 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4437 __ bind(&have_value);
4438 }
4439
4440 __ movdbl(double_store_operand, value);
4441 } else {
4442 // Can't use SSE2 in the serializer
4443 if (instr->hydrogen()->IsConstantHoleStore()) {
4444 // This means we should store the (double) hole. No floating point
4445 // registers required.
4446 double nan_double = FixedDoubleArray::hole_nan_as_double();
4447 uint64_t int_val = BitCast<uint64_t, double>(nan_double);
4448 int32_t lower = static_cast<int32_t>(int_val);
4449 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
4450
4451 __ mov(double_store_operand, Immediate(lower));
4452 Operand double_store_operand2 = BuildFastArrayOperand(
4453 instr->elements(),
4454 instr->key(),
4455 instr->hydrogen()->key()->representation(),
4456 FAST_DOUBLE_ELEMENTS,
4457 FixedDoubleArray::kHeaderSize - kHeapObjectTag + kPointerSize,
4458 instr->additional_index());
4459 __ mov(double_store_operand2, Immediate(upper));
4460 } else {
4461 Label no_special_nan_handling;
4462 ASSERT(x87_stack_depth_ > 0);
4463
4464 if (instr->NeedsCanonicalization()) {
4465 __ fld(0);
4466 __ fld(0);
4467 __ FCmp();
4468
4469 __ j(parity_odd, &no_special_nan_handling);
4470 __ sub(esp, Immediate(kDoubleSize));
4471 __ fst_d(MemOperand(esp, 0));
4472 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4473 Immediate(kHoleNanUpper32));
4474 __ add(esp, Immediate(kDoubleSize));
4475 Label canonicalize;
4476 __ j(not_equal, &canonicalize);
4477 __ jmp(&no_special_nan_handling);
4478 __ bind(&canonicalize);
4479 __ fstp(0);
4480 __ fld_d(Operand::StaticVariable(canonical_nan_reference));
4481 }
4482
4483 __ bind(&no_special_nan_handling);
4484 __ fst_d(double_store_operand);
4485 }
4486 }
4377 } 4487 }
4378 4488
4379 4489
4380 void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { 4490 void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4381 Register value = ToRegister(instr->value()); 4491 Register value = ToRegister(instr->value());
4382 Register elements = ToRegister(instr->elements()); 4492 Register elements = ToRegister(instr->elements());
4383 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; 4493 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4384 4494
4385 Operand operand = BuildFastArrayOperand( 4495 Operand operand = BuildFastArrayOperand(
4386 instr->elements(), 4496 instr->elements(),
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
4798 4908
4799 Label no_special_nan_handling; 4909 Label no_special_nan_handling;
4800 Label done; 4910 Label done;
4801 if (convert_hole) { 4911 if (convert_hole) {
4802 bool use_sse2 = CpuFeatures::IsSupported(SSE2); 4912 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
4803 if (use_sse2) { 4913 if (use_sse2) {
4804 CpuFeatureScope scope(masm(), SSE2); 4914 CpuFeatureScope scope(masm(), SSE2);
4805 XMMRegister input_reg = ToDoubleRegister(instr->value()); 4915 XMMRegister input_reg = ToDoubleRegister(instr->value());
4806 __ ucomisd(input_reg, input_reg); 4916 __ ucomisd(input_reg, input_reg);
4807 } else { 4917 } else {
4808 if (!IsX87TopOfStack(instr->value())) {
4809 __ fld_d(ToOperand(instr->value()));
4810 }
4811 __ fld(0); 4918 __ fld(0);
4812 __ fld(0); 4919 __ fld(0);
4813 __ FCmp(); 4920 __ FCmp();
4814 } 4921 }
4815 4922
4816 __ j(parity_odd, &no_special_nan_handling); 4923 __ j(parity_odd, &no_special_nan_handling);
4817 __ sub(esp, Immediate(kDoubleSize)); 4924 __ sub(esp, Immediate(kDoubleSize));
4818 if (use_sse2) { 4925 if (use_sse2) {
4819 CpuFeatureScope scope(masm(), SSE2); 4926 CpuFeatureScope scope(masm(), SSE2);
4820 XMMRegister input_reg = ToDoubleRegister(instr->value()); 4927 XMMRegister input_reg = ToDoubleRegister(instr->value());
4821 __ movdbl(MemOperand(esp, 0), input_reg); 4928 __ movdbl(MemOperand(esp, 0), input_reg);
4822 } else { 4929 } else {
4823 __ fld(0); 4930 __ fld(0);
4824 __ fstp_d(MemOperand(esp, 0)); 4931 __ fstp_d(MemOperand(esp, 0));
4825 } 4932 }
4826 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)), 4933 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4827 Immediate(kHoleNanUpper32)); 4934 Immediate(kHoleNanUpper32));
4828 Label canonicalize; 4935 Label canonicalize;
4829 __ j(not_equal, &canonicalize); 4936 __ j(not_equal, &canonicalize);
4830 __ add(esp, Immediate(kDoubleSize)); 4937 __ add(esp, Immediate(kDoubleSize));
4831 __ mov(reg, factory()->the_hole_value()); 4938 __ mov(reg, factory()->the_hole_value());
4939 if (!use_sse2) {
4940 __ fstp(0);
4941 }
4832 __ jmp(&done); 4942 __ jmp(&done);
4833 __ bind(&canonicalize); 4943 __ bind(&canonicalize);
4834 __ add(esp, Immediate(kDoubleSize)); 4944 __ add(esp, Immediate(kDoubleSize));
4835 ExternalReference nan = 4945 ExternalReference nan =
4836 ExternalReference::address_of_canonical_non_hole_nan(); 4946 ExternalReference::address_of_canonical_non_hole_nan();
4837 if (use_sse2) { 4947 if (use_sse2) {
4838 CpuFeatureScope scope(masm(), SSE2); 4948 CpuFeatureScope scope(masm(), SSE2);
4839 XMMRegister input_reg = ToDoubleRegister(instr->value()); 4949 XMMRegister input_reg = ToDoubleRegister(instr->value());
4840 __ movdbl(input_reg, Operand::StaticVariable(nan)); 4950 __ movdbl(input_reg, Operand::StaticVariable(nan));
4841 } else { 4951 } else {
4842 __ fstp(0); 4952 __ fstp(0);
4843 __ fld_d(Operand::StaticVariable(nan)); 4953 __ fld_d(Operand::StaticVariable(nan));
4844 } 4954 }
4845 } 4955 }
4846 4956
4847 __ bind(&no_special_nan_handling); 4957 __ bind(&no_special_nan_handling);
4848 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); 4958 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
4849 if (FLAG_inline_new) { 4959 if (FLAG_inline_new) {
4850 Register tmp = ToRegister(instr->temp()); 4960 Register tmp = ToRegister(instr->temp());
4851 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry()); 4961 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4852 } else { 4962 } else {
4853 __ jmp(deferred->entry()); 4963 __ jmp(deferred->entry());
4854 } 4964 }
4855 __ bind(deferred->exit()); 4965 __ bind(deferred->exit());
4856 if (CpuFeatures::IsSupported(SSE2)) { 4966 if (CpuFeatures::IsSupported(SSE2)) {
4857 CpuFeatureScope scope(masm(), SSE2); 4967 CpuFeatureScope scope(masm(), SSE2);
4858 XMMRegister input_reg = ToDoubleRegister(instr->value()); 4968 XMMRegister input_reg = ToDoubleRegister(instr->value());
4859 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); 4969 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4860 } else { 4970 } else {
4861 if (!IsX87TopOfStack(instr->value())) { 4971 __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
4862 __ fld_d(ToOperand(instr->value()));
4863 }
4864 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4865 } 4972 }
4866 __ bind(&done); 4973 __ bind(&done);
4867 } 4974 }
4868 4975
4869 4976
4870 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { 4977 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4871 // TODO(3095996): Get rid of this. For now, we need to make the 4978 // TODO(3095996): Get rid of this. For now, we need to make the
4872 // result register contain a valid pointer because it is already 4979 // result register contain a valid pointer because it is already
4873 // contained in the register pointer map. 4980 // contained in the register pointer map.
4874 Register reg = ToRegister(instr->result()); 4981 Register reg = ToRegister(instr->result());
(...skipping 27 matching lines...) Expand all
4902 if (instr->needs_check()) { 5009 if (instr->needs_check()) {
4903 __ test(ToRegister(input), Immediate(kSmiTagMask)); 5010 __ test(ToRegister(input), Immediate(kSmiTagMask));
4904 DeoptimizeIf(not_zero, instr->environment()); 5011 DeoptimizeIf(not_zero, instr->environment());
4905 } else { 5012 } else {
4906 __ AssertSmi(ToRegister(input)); 5013 __ AssertSmi(ToRegister(input));
4907 } 5014 }
4908 __ SmiUntag(ToRegister(input)); 5015 __ SmiUntag(ToRegister(input));
4909 } 5016 }
4910 5017
4911 5018
5019 void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
5020 Register temp_reg,
5021 bool deoptimize_on_undefined,
5022 bool deoptimize_on_minus_zero,
5023 LEnvironment* env,
5024 NumberUntagDMode mode) {
5025 Label load_smi, done;
5026
5027 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
5028 // Smi check.
5029 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
5030
5031 // Heap number map check.
5032 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5033 factory()->heap_number_map());
5034 if (deoptimize_on_undefined) {
5035 DeoptimizeIf(not_equal, env);
5036 } else {
5037 Label heap_number;
5038 __ j(equal, &heap_number, Label::kNear);
5039
5040 __ cmp(input_reg, factory()->undefined_value());
5041 DeoptimizeIf(not_equal, env);
5042
5043 // Convert undefined to NaN.
5044 ExternalReference nan =
5045 ExternalReference::address_of_canonical_non_hole_nan();
5046 __ fld_d(Operand::StaticVariable(nan));
5047 __ jmp(&done, Label::kNear);
5048 __ bind(&heap_number);
5049 }
5050 // Heap number to x87 conversion.
5051 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5052 if (deoptimize_on_minus_zero) {
5053 __ fldz();
5054 __ FCmp();
5055 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5056 __ j(not_zero, &done, Label::kNear);
5057
5058 // Use general purpose registers to check if we have -0.0
5059 __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5060 __ test(temp_reg, Immediate(HeapNumber::kSignMask));
5061 __ j(zero, &done, Label::kNear);
5062
5063 // Pop FPU stack before deoptimizing.
5064 __ fstp(0);
5065 DeoptimizeIf(not_zero, env);
5066 }
5067 __ jmp(&done, Label::kNear);
5068 } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
5069 __ test(input_reg, Immediate(kSmiTagMask));
5070 DeoptimizeIf(not_equal, env);
5071 } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
5072 __ test(input_reg, Immediate(kSmiTagMask));
5073 __ j(zero, &load_smi);
5074 ExternalReference hole_nan_reference =
5075 ExternalReference::address_of_the_hole_nan();
5076 __ fld_d(Operand::StaticVariable(hole_nan_reference));
5077 __ jmp(&done, Label::kNear);
5078 } else {
5079 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
5080 }
5081
5082 __ bind(&load_smi);
5083 __ SmiUntag(input_reg); // Untag smi before converting to float.
5084 __ push(input_reg);
5085 __ fild_s(Operand(esp, 0));
5086 __ pop(input_reg);
5087 __ SmiTag(input_reg); // Retag smi.
5088 __ bind(&done);
5089 }
5090
5091
4912 void LCodeGen::EmitNumberUntagD(Register input_reg, 5092 void LCodeGen::EmitNumberUntagD(Register input_reg,
4913 Register temp_reg, 5093 Register temp_reg,
4914 XMMRegister result_reg, 5094 XMMRegister result_reg,
4915 bool deoptimize_on_undefined, 5095 bool deoptimize_on_undefined,
4916 bool deoptimize_on_minus_zero, 5096 bool deoptimize_on_minus_zero,
4917 LEnvironment* env, 5097 LEnvironment* env,
4918 NumberUntagDMode mode) { 5098 NumberUntagDMode mode) {
4919 Label load_smi, done; 5099 Label load_smi, done;
4920 5100
4921 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { 5101 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
5014 __ RecordComment("Deferred TaggedToI: exponent too big"); 5194 __ RecordComment("Deferred TaggedToI: exponent too big");
5015 DeoptimizeIf(no_condition, instr->environment()); 5195 DeoptimizeIf(no_condition, instr->environment());
5016 5196
5017 // Reserve space for 64 bit answer. 5197 // Reserve space for 64 bit answer.
5018 __ bind(&convert); 5198 __ bind(&convert);
5019 __ sub(Operand(esp), Immediate(kDoubleSize)); 5199 __ sub(Operand(esp), Immediate(kDoubleSize));
5020 // Do conversion, which cannot fail because we checked the exponent. 5200 // Do conversion, which cannot fail because we checked the exponent.
5021 __ fisttp_d(Operand(esp, 0)); 5201 __ fisttp_d(Operand(esp, 0));
5022 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result. 5202 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
5023 __ add(Operand(esp), Immediate(kDoubleSize)); 5203 __ add(Operand(esp), Immediate(kDoubleSize));
5024 } else { 5204 } else if (CpuFeatures::IsSupported(SSE2)) {
5025 CpuFeatureScope scope(masm(), SSE2); 5205 CpuFeatureScope scope(masm(), SSE2);
5026 XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); 5206 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
5027 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 5207 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5028 __ cvttsd2si(input_reg, Operand(xmm0)); 5208 __ cvttsd2si(input_reg, Operand(xmm0));
5029 __ cmp(input_reg, 0x80000000u); 5209 __ cmp(input_reg, 0x80000000u);
5030 __ j(not_equal, &done); 5210 __ j(not_equal, &done);
5031 // Check if the input was 0x8000000 (kMinInt). 5211 // Check if the input was 0x8000000 (kMinInt).
5032 // If no, then we got an overflow and we deoptimize. 5212 // If no, then we got an overflow and we deoptimize.
5033 ExternalReference min_int = ExternalReference::address_of_min_int(); 5213 ExternalReference min_int = ExternalReference::address_of_min_int();
5034 __ movdbl(xmm_temp, Operand::StaticVariable(min_int)); 5214 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
5035 __ ucomisd(xmm_temp, xmm0); 5215 __ ucomisd(xmm_temp, xmm0);
5036 DeoptimizeIf(not_equal, instr->environment()); 5216 DeoptimizeIf(not_equal, instr->environment());
5037 DeoptimizeIf(parity_even, instr->environment()); // NaN. 5217 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5218 } else {
5219 UNREACHABLE();
5038 } 5220 }
5039 } else if (CpuFeatures::IsSupported(SSE2)) { 5221 } else if (CpuFeatures::IsSupported(SSE2)) {
5040 CpuFeatureScope scope(masm(), SSE2); 5222 CpuFeatureScope scope(masm(), SSE2);
5041 // Deoptimize if we don't have a heap number. 5223 // Deoptimize if we don't have a heap number.
5042 __ RecordComment("Deferred TaggedToI: not a heap number"); 5224 __ RecordComment("Deferred TaggedToI: not a heap number");
5043 DeoptimizeIf(not_equal, instr->environment()); 5225 DeoptimizeIf(not_equal, instr->environment());
5044 5226
5045 XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); 5227 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
5046 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 5228 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5047 __ cvttsd2si(input_reg, Operand(xmm0)); 5229 __ cvttsd2si(input_reg, Operand(xmm0));
(...skipping 24 matching lines...) Expand all
5072 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) 5254 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
5073 : LDeferredCode(codegen), instr_(instr) { } 5255 : LDeferredCode(codegen), instr_(instr) { }
5074 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } 5256 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
5075 virtual LInstruction* instr() { return instr_; } 5257 virtual LInstruction* instr() { return instr_; }
5076 private: 5258 private:
5077 LTaggedToI* instr_; 5259 LTaggedToI* instr_;
5078 }; 5260 };
5079 5261
5080 LOperand* input = instr->value(); 5262 LOperand* input = instr->value();
5081 ASSERT(input->IsRegister()); 5263 ASSERT(input->IsRegister());
5082 ASSERT(input->Equals(instr->result()));
5083
5084 Register input_reg = ToRegister(input); 5264 Register input_reg = ToRegister(input);
5265 ASSERT(input_reg.is(ToRegister(instr->result())));
5085 5266
5086 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); 5267 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
5087 5268
5088 // Smi check.
5089 __ JumpIfNotSmi(input_reg, deferred->entry()); 5269 __ JumpIfNotSmi(input_reg, deferred->entry());
5090 5270 __ SmiUntag(input_reg);
5091 // Smi to int32 conversion
5092 __ SmiUntag(input_reg); // Untag smi.
5093
5094 __ bind(deferred->exit()); 5271 __ bind(deferred->exit());
5095 } 5272 }
5096 5273
5274
5275 void LCodeGen::DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
5276 Label done, heap_number;
5277 Register result_reg = ToRegister(instr->result());
5278 Register input_reg = ToRegister(instr->value());
5279
5280 // Heap number map check.
5281 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5282 factory()->heap_number_map());
5283 __ j(equal, &heap_number, Label::kNear);
5284 // Check for undefined. Undefined is converted to zero for truncating
5285 // conversions.
5286 __ cmp(input_reg, factory()->undefined_value());
5287 __ RecordComment("Deferred TaggedToI: cannot truncate");
5288 DeoptimizeIf(not_equal, instr->environment());
5289 __ xor_(result_reg, result_reg);
5290 __ jmp(&done, Label::kFar);
5291 __ bind(&heap_number);
5292
5293 // Surprisingly, all of this crazy bit manipulation is considerably
5294 // faster than using the built-in x86 CPU conversion functions (about 6x).
5295 Label right_exponent, adjust_bias, zero_result;
5296 Register scratch = ToRegister(instr->scratch());
5297 Register scratch2 = ToRegister(instr->scratch2());
5298 // Get exponent word.
5299 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5300 // Get exponent alone in scratch2.
5301 __ mov(scratch2, scratch);
5302 __ and_(scratch2, HeapNumber::kExponentMask);
5303 __ shr(scratch2, HeapNumber::kExponentShift);
5304 if (instr->truncating()) {
5305 __ j(zero, &zero_result);
5306 } else {
5307 __ j(not_zero, &adjust_bias);
5308 __ test(scratch, Immediate(HeapNumber::kMantissaMask));
5309 DeoptimizeIf(not_zero, instr->environment());
5310 __ cmp(FieldOperand(input_reg, HeapNumber::kMantissaOffset), Immediate(0));
5311 DeoptimizeIf(not_equal, instr->environment());
5312 __ bind(&adjust_bias);
5313 }
5314 __ sub(scratch2, Immediate(HeapNumber::kExponentBias));
5315 if (!instr->truncating()) {
5316 DeoptimizeIf(negative, instr->environment());
5317 } else {
5318 __ j(negative, &zero_result);
5319 }
5320
5321 // Get the second half of the double. For some exponents we don't
5322 // actually need this because the bits get shifted out again, but
5323 // it's probably slower to test than just to do it.
5324 Register scratch3 = ToRegister(instr->scratch3());
5325 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5326 __ xor_(result_reg, result_reg);
5327
5328 const uint32_t non_int32_exponent = 31;
5329 __ cmp(scratch2, Immediate(non_int32_exponent));
5330 // If we have a match of the int32 exponent then skip some logic.
5331 __ j(equal, &right_exponent, Label::kNear);
5332 // If the number doesn't find in an int32, deopt.
5333 DeoptimizeIf(greater, instr->environment());
5334
5335 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
5336 // < 31.
5337 __ mov(result_reg, Immediate(31));
5338 __ sub(result_reg, scratch2);
5339
5340 __ bind(&right_exponent);
5341
5342 // Save off exponent for negative check later.
5343 __ mov(scratch2, scratch);
5344
5345 // Here result_reg is the shift, scratch is the exponent word.
5346 // Get the top bits of the mantissa.
5347 __ and_(scratch, HeapNumber::kMantissaMask);
5348 // Put back the implicit 1.
5349 __ or_(scratch, 1 << HeapNumber::kExponentShift);
5350 // Shift up the mantissa bits to take up the space the exponent used to
5351 // take. We have kExponentShift + 1 significant bits int he low end of the
5352 // word. Shift them to the top bits.
5353 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
5354 __ shl(scratch, shift_distance);
5355 if (!instr->truncating()) {
5356 // If not truncating, a non-zero value in the bottom 22 bits means a
5357 // non-integral value --> trigger a deopt.
5358 __ test(scratch3, Immediate((1 << (32 - shift_distance)) - 1));
5359 DeoptimizeIf(not_equal, instr->environment());
5360 }
5361 // Shift down 22 bits to get the most significant 10 bits or the low
5362 // mantissa word.
5363 __ shr(scratch3, 32 - shift_distance);
5364 __ or_(scratch3, scratch);
5365 if (!instr->truncating()) {
5366 // If truncating, a non-zero value in the bits that will be shifted away
5367 // when adjusting the exponent means rounding --> deopt.
5368 __ mov(scratch, 0x1);
5369 ASSERT(result_reg.is(ecx));
5370 __ shl_cl(scratch);
5371 __ dec(scratch);
5372 __ test(scratch3, scratch);
5373 DeoptimizeIf(not_equal, instr->environment());
5374 }
5375 // Move down according to the exponent.
5376 ASSERT(result_reg.is(ecx));
5377 __ shr_cl(scratch3);
5378 // Now the unsigned 32-bit answer is in scratch3. We need to move it to
5379 // result_reg and we may need to fix the sign.
5380 Label negative_result;
5381 __ xor_(result_reg, result_reg);
5382 __ cmp(scratch2, result_reg);
5383 __ j(less, &negative_result, Label::kNear);
5384 __ cmp(scratch3, result_reg);
5385 __ mov(result_reg, scratch3);
5386 // If the result is > MAX_INT, result doesn't fit in signed 32-bit --> deopt.
5387 DeoptimizeIf(less, instr->environment());
5388 __ jmp(&done, Label::kNear);
5389 __ bind(&zero_result);
5390 __ xor_(result_reg, result_reg);
5391 __ jmp(&done, Label::kNear);
5392 __ bind(&negative_result);
5393 __ sub(result_reg, scratch3);
5394 if (!instr->truncating()) {
5395 // -0.0 triggers a deopt.
5396 DeoptimizeIf(zero, instr->environment());
5397 }
5398 // If the negative subtraction overflows into a positive number, there was an
5399 // overflow --> deopt.
5400 DeoptimizeIf(positive, instr->environment());
5401 __ bind(&done);
5402 }
5403
5404
5405 void LCodeGen::DoTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
5406 class DeferredTaggedToINoSSE2: public LDeferredCode {
5407 public:
5408 DeferredTaggedToINoSSE2(LCodeGen* codegen, LTaggedToINoSSE2* instr)
5409 : LDeferredCode(codegen), instr_(instr) { }
5410 virtual void Generate() { codegen()->DoDeferredTaggedToINoSSE2(instr_); }
5411 virtual LInstruction* instr() { return instr_; }
5412 private:
5413 LTaggedToINoSSE2* instr_;
5414 };
5415
5416 LOperand* input = instr->value();
5417 ASSERT(input->IsRegister());
5418 Register input_reg = ToRegister(input);
5419 ASSERT(input_reg.is(ToRegister(instr->result())));
5420
5421 DeferredTaggedToINoSSE2* deferred =
5422 new(zone()) DeferredTaggedToINoSSE2(this, instr);
5423
5424 // Smi check.
5425 __ JumpIfNotSmi(input_reg, deferred->entry());
5426 __ SmiUntag(input_reg); // Untag smi.
5427 __ bind(deferred->exit());
5428 }
5429
5097 5430
5098 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { 5431 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
5099 LOperand* input = instr->value(); 5432 LOperand* input = instr->value();
5100 ASSERT(input->IsRegister()); 5433 ASSERT(input->IsRegister());
5101 LOperand* temp = instr->temp(); 5434 LOperand* temp = instr->temp();
5102 ASSERT(temp == NULL || temp->IsRegister()); 5435 ASSERT(temp == NULL || temp->IsRegister());
5103 LOperand* result = instr->result(); 5436 LOperand* result = instr->result();
5104 ASSERT(result->IsDoubleRegister()); 5437 ASSERT(result->IsDoubleRegister());
5105 5438
5439 Register input_reg = ToRegister(input);
5440 bool deoptimize_on_minus_zero =
5441 instr->hydrogen()->deoptimize_on_minus_zero();
5442 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
5443
5444 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5445 HValue* value = instr->hydrogen()->value();
5446 if (value->type().IsSmi()) {
5447 if (value->IsLoadKeyed()) {
5448 HLoadKeyed* load = HLoadKeyed::cast(value);
5449 if (load->UsesMustHandleHole()) {
5450 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
5451 mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
5452 } else {
5453 mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
5454 }
5455 } else {
5456 mode = NUMBER_CANDIDATE_IS_SMI;
5457 }
5458 }
5459 }
5460
5106 if (CpuFeatures::IsSupported(SSE2)) { 5461 if (CpuFeatures::IsSupported(SSE2)) {
5107 CpuFeatureScope scope(masm(), SSE2); 5462 CpuFeatureScope scope(masm(), SSE2);
5108 Register input_reg = ToRegister(input);
5109 XMMRegister result_reg = ToDoubleRegister(result); 5463 XMMRegister result_reg = ToDoubleRegister(result);
5110
5111 bool deoptimize_on_minus_zero =
5112 instr->hydrogen()->deoptimize_on_minus_zero();
5113 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
5114
5115 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5116 HValue* value = instr->hydrogen()->value();
5117 if (value->type().IsSmi()) {
5118 if (value->IsLoadKeyed()) {
5119 HLoadKeyed* load = HLoadKeyed::cast(value);
5120 if (load->UsesMustHandleHole()) {
5121 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
5122 mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
5123 } else {
5124 mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
5125 }
5126 } else {
5127 mode = NUMBER_CANDIDATE_IS_SMI;
5128 }
5129 }
5130 }
5131
5132 EmitNumberUntagD(input_reg, 5464 EmitNumberUntagD(input_reg,
5133 temp_reg, 5465 temp_reg,
5134 result_reg, 5466 result_reg,
5135 instr->hydrogen()->deoptimize_on_undefined(), 5467 instr->hydrogen()->deoptimize_on_undefined(),
5136 deoptimize_on_minus_zero, 5468 deoptimize_on_minus_zero,
5137 instr->environment(), 5469 instr->environment(),
5138 mode); 5470 mode);
5139 } else { 5471 } else {
5140 UNIMPLEMENTED(); 5472 EmitNumberUntagDNoSSE2(input_reg,
5473 temp_reg,
5474 instr->hydrogen()->deoptimize_on_undefined(),
5475 deoptimize_on_minus_zero,
5476 instr->environment(),
5477 mode);
5478 CurrentInstructionReturnsX87Result();
5141 } 5479 }
5142 } 5480 }
5143 5481
5144 5482
5145 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { 5483 void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
5146 LOperand* input = instr->value(); 5484 LOperand* input = instr->value();
5147 ASSERT(input->IsDoubleRegister()); 5485 ASSERT(input->IsDoubleRegister());
5148 LOperand* result = instr->result(); 5486 LOperand* result = instr->result();
5149 ASSERT(result->IsRegister()); 5487 ASSERT(result->IsRegister());
5150 CpuFeatureScope scope(masm(), SSE2); 5488 CpuFeatureScope scope(masm(), SSE2);
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
5402 // Heap number 5740 // Heap number
5403 __ bind(&heap_number); 5741 __ bind(&heap_number);
5404 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 5742 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5405 __ ClampDoubleToUint8(xmm0, xmm1, input_reg); 5743 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
5406 __ jmp(&done, Label::kNear); 5744 __ jmp(&done, Label::kNear);
5407 5745
5408 // smi 5746 // smi
5409 __ bind(&is_smi); 5747 __ bind(&is_smi);
5410 __ SmiUntag(input_reg); 5748 __ SmiUntag(input_reg);
5411 __ ClampUint8(input_reg); 5749 __ ClampUint8(input_reg);
5412
5413 __ bind(&done); 5750 __ bind(&done);
5414 } 5751 }
5415 5752
5753
5754 void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
5755 Register input_reg = ToRegister(instr->unclamped());
5756 Register result_reg = ToRegister(instr->result());
5757 Register scratch = ToRegister(instr->scratch());
5758 Register scratch2 = ToRegister(instr->scratch2());
5759 Register scratch3 = ToRegister(instr->scratch3());
5760 Label is_smi, done, heap_number, valid_exponent,
5761 largest_value, zero_result, maybe_nan_or_infinity;
5762
5763 __ JumpIfSmi(input_reg, &is_smi);
5764
5765 // Check for heap number
5766 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5767 factory()->heap_number_map());
5768 __ j(equal, &heap_number, Label::kFar);
5769
5770 // Check for undefined. Undefined is converted to zero for clamping
5771 // conversions.
5772 __ cmp(input_reg, factory()->undefined_value());
5773 DeoptimizeIf(not_equal, instr->environment());
5774 __ jmp(&zero_result);
5775
5776 // Heap number
5777 __ bind(&heap_number);
5778
5779 // Surprisingly, all of the hand-crafted bit-manipulations below are much
5780 // faster than the x86 FPU built-in instruction, especially since "banker's
5781 // rounding" would be additionally very expensive
5782
5783 // Get exponent word.
5784 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5785 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5786
5787 // Test for negative values --> clamp to zero
5788 __ test(scratch, scratch);
5789 __ j(negative, &zero_result);
5790
5791 // Get exponent alone in scratch2.
5792 __ mov(scratch2, scratch);
5793 __ and_(scratch2, HeapNumber::kExponentMask);
5794 __ shr(scratch2, HeapNumber::kExponentShift);
5795 __ j(zero, &zero_result);
5796 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1));
5797 __ j(negative, &zero_result);
5798
5799 const uint32_t non_int8_exponent = 7;
5800 __ cmp(scratch2, Immediate(non_int8_exponent + 1));
5801 // If the exponent is too big, check for special values.
5802 __ j(greater, &maybe_nan_or_infinity, Label::kNear);
5803
5804 __ bind(&valid_exponent);
5805 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
5806 // < 7. The shift bias is the number of bits to shift the mantissa such that
5807 // with an exponent of 7 such the that top-most one is in bit 30, allowing
5808 // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to
5809 // 1).
5810 int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1;
5811 __ lea(result_reg, MemOperand(scratch2, shift_bias));
5812 // Here result_reg (ecx) is the shift, scratch is the exponent word. Get the
5813 // top bits of the mantissa.
5814 __ and_(scratch, HeapNumber::kMantissaMask);
5815 // Put back the implicit 1 of the mantissa
5816 __ or_(scratch, 1 << HeapNumber::kExponentShift);
5817 // Shift up to round
5818 __ shl_cl(scratch);
5819 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then
5820 // use the bit in the "ones" place and add it to the "halves" place, which has
5821 // the effect of rounding to even.
5822 __ mov(scratch2, scratch);
5823 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8;
5824 const uint32_t one_bit_shift = one_half_bit_shift + 1;
5825 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1));
5826 __ cmp(scratch2, Immediate(1 << one_half_bit_shift));
5827 Label no_round;
5828 __ j(less, &no_round);
5829 Label round_up;
5830 __ mov(scratch2, Immediate(1 << one_half_bit_shift));
5831 __ j(greater, &round_up);
5832 __ test(scratch3, scratch3);
5833 __ j(not_zero, &round_up);
5834 __ mov(scratch2, scratch);
5835 __ and_(scratch2, Immediate(1 << one_bit_shift));
5836 __ shr(scratch2, 1);
5837 __ bind(&round_up);
5838 __ add(scratch, scratch2);
5839 __ j(overflow, &largest_value);
5840 __ bind(&no_round);
5841 __ shr(scratch, 23);
5842 __ mov(result_reg, scratch);
5843 __ jmp(&done, Label::kNear);
5844
5845 __ bind(&maybe_nan_or_infinity);
5846 // Check for NaN/Infinity, all other values map to 255
5847 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1));
5848 __ j(not_equal, &largest_value, Label::kNear);
5849
5850 // Check for NaN, which differs from Infinity in that at least one mantissa
5851 // bit is set.
5852 __ and_(scratch, HeapNumber::kMantissaMask);
5853 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5854 __ j(not_zero, &zero_result); // M!=0 --> NaN
5855 // Infinity -> Fall through to map to 255.
5856
5857 __ bind(&largest_value);
5858 __ mov(result_reg, Immediate(255));
5859 __ jmp(&done, Label::kNear);
5860
5861 __ bind(&zero_result);
5862 __ xor_(result_reg, result_reg);
5863 __ jmp(&done);
5864
5865 // smi
5866 __ bind(&is_smi);
5867 if (!input_reg.is(result_reg)) {
5868 __ mov(result_reg, input_reg);
5869 }
5870 __ SmiUntag(result_reg);
5871 __ ClampUint8(result_reg);
5872 __ bind(&done);
5873 }
5874
5416 5875
5417 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { 5876 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
5418 Register reg = ToRegister(instr->temp()); 5877 Register reg = ToRegister(instr->temp());
5419 5878
5420 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); 5879 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5421 ZoneList<Handle<Map> >* maps = instr->maps(); 5880 ZoneList<Handle<Map> >* maps = instr->maps();
5422 5881
5423 ASSERT(prototypes->length() == maps->length()); 5882 ASSERT(prototypes->length() == maps->length());
5424 5883
5425 if (instr->hydrogen()->CanOmitPrototypeChecks()) { 5884 if (instr->hydrogen()->CanOmitPrototypeChecks()) {
(...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after
6293 FixedArray::kHeaderSize - kPointerSize)); 6752 FixedArray::kHeaderSize - kPointerSize));
6294 __ bind(&done); 6753 __ bind(&done);
6295 } 6754 }
6296 6755
6297 6756
6298 #undef __ 6757 #undef __
6299 6758
6300 } } // namespace v8::internal 6759 } } // namespace v8::internal
6301 6760
6302 #endif // V8_TARGET_ARCH_IA32 6761 #endif // V8_TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698