| OLD | NEW |
| 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 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 ASSERT(info()->IsStub()); | 439 ASSERT(info()->IsStub()); |
| 440 frame_is_built_ = true; | 440 frame_is_built_ = true; |
| 441 // Build the frame in such a way that esi isn't trashed. | 441 // Build the frame in such a way that esi isn't trashed. |
| 442 __ push(ebp); // Caller's frame pointer. | 442 __ push(ebp); // Caller's frame pointer. |
| 443 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); | 443 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 444 __ push(Immediate(Smi::FromInt(StackFrame::STUB))); | 444 __ push(Immediate(Smi::FromInt(StackFrame::STUB))); |
| 445 __ lea(ebp, Operand(esp, 2 * kPointerSize)); | 445 __ lea(ebp, Operand(esp, 2 * kPointerSize)); |
| 446 Comment(";;; Deferred code"); | 446 Comment(";;; Deferred code"); |
| 447 } | 447 } |
| 448 code->Generate(); | 448 code->Generate(); |
| 449 __ bind(code->done()); |
| 449 if (NeedsDeferredFrame()) { | 450 if (NeedsDeferredFrame()) { |
| 450 Comment(";;; Destroy frame"); | 451 Comment(";;; Destroy frame"); |
| 451 ASSERT(frame_is_built_); | 452 ASSERT(frame_is_built_); |
| 452 frame_is_built_ = false; | 453 frame_is_built_ = false; |
| 453 __ mov(esp, ebp); | 454 __ mov(esp, ebp); |
| 454 __ pop(ebp); | 455 __ pop(ebp); |
| 455 } | 456 } |
| 456 __ jmp(code->exit()); | 457 __ jmp(code->exit()); |
| 457 } | 458 } |
| 458 } | 459 } |
| (...skipping 4807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5266 | 5267 |
| 5267 // Smi to XMM conversion | 5268 // Smi to XMM conversion |
| 5268 __ bind(&load_smi); | 5269 __ bind(&load_smi); |
| 5269 __ SmiUntag(input_reg); // Untag smi before converting to float. | 5270 __ SmiUntag(input_reg); // Untag smi before converting to float. |
| 5270 __ cvtsi2sd(result_reg, Operand(input_reg)); | 5271 __ cvtsi2sd(result_reg, Operand(input_reg)); |
| 5271 __ SmiTag(input_reg); // Retag smi. | 5272 __ SmiTag(input_reg); // Retag smi. |
| 5272 __ bind(&done); | 5273 __ bind(&done); |
| 5273 } | 5274 } |
| 5274 | 5275 |
| 5275 | 5276 |
| 5276 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { | 5277 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) { |
| 5277 Label done, heap_number; | |
| 5278 Register input_reg = ToRegister(instr->value()); | 5278 Register input_reg = ToRegister(instr->value()); |
| 5279 | 5279 |
| 5280 // Heap number map check. | |
| 5281 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | |
| 5282 factory()->heap_number_map()); | |
| 5283 | 5280 |
| 5284 if (instr->truncating()) { | 5281 if (instr->truncating()) { |
| 5282 Label heap_number, slow_case; |
| 5283 |
| 5284 // Heap number map check. |
| 5285 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 5286 factory()->heap_number_map()); |
| 5285 __ j(equal, &heap_number, Label::kNear); | 5287 __ j(equal, &heap_number, Label::kNear); |
| 5288 |
| 5286 // Check for undefined. Undefined is converted to zero for truncating | 5289 // Check for undefined. Undefined is converted to zero for truncating |
| 5287 // conversions. | 5290 // conversions. |
| 5288 __ cmp(input_reg, factory()->undefined_value()); | 5291 __ cmp(input_reg, factory()->undefined_value()); |
| 5289 __ RecordComment("Deferred TaggedToI: cannot truncate"); | 5292 __ RecordComment("Deferred TaggedToI: cannot truncate"); |
| 5290 DeoptimizeIf(not_equal, instr->environment()); | 5293 DeoptimizeIf(not_equal, instr->environment()); |
| 5291 __ mov(input_reg, 0); | 5294 __ mov(input_reg, 0); |
| 5292 __ jmp(&done, Label::kNear); | 5295 __ jmp(done); |
| 5293 | 5296 |
| 5294 __ bind(&heap_number); | 5297 __ bind(&heap_number); |
| 5295 if (CpuFeatures::IsSupported(SSE3)) { | 5298 __ TruncateHeapNumberToI(input_reg, input_reg); |
| 5296 CpuFeatureScope scope(masm(), SSE3); | |
| 5297 Label convert; | |
| 5298 // Use more powerful conversion when sse3 is available. | |
| 5299 // Load x87 register with heap number. | |
| 5300 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); | |
| 5301 // Get exponent alone and check for too-big exponent. | |
| 5302 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | |
| 5303 __ and_(input_reg, HeapNumber::kExponentMask); | |
| 5304 const uint32_t kTooBigExponent = | |
| 5305 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | |
| 5306 __ cmp(Operand(input_reg), Immediate(kTooBigExponent)); | |
| 5307 __ j(less, &convert, Label::kNear); | |
| 5308 // Pop FPU stack before deoptimizing. | |
| 5309 __ fstp(0); | |
| 5310 __ RecordComment("Deferred TaggedToI: exponent too big"); | |
| 5311 DeoptimizeIf(no_condition, instr->environment()); | |
| 5312 | |
| 5313 // Reserve space for 64 bit answer. | |
| 5314 __ bind(&convert); | |
| 5315 __ sub(Operand(esp), Immediate(kDoubleSize)); | |
| 5316 // Do conversion, which cannot fail because we checked the exponent. | |
| 5317 __ fisttp_d(Operand(esp, 0)); | |
| 5318 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result. | |
| 5319 __ add(Operand(esp), Immediate(kDoubleSize)); | |
| 5320 } else if (CpuFeatures::IsSupported(SSE2)) { | |
| 5321 CpuFeatureScope scope(masm(), SSE2); | |
| 5322 XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); | |
| 5323 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | |
| 5324 __ cvttsd2si(input_reg, Operand(xmm0)); | |
| 5325 __ cmp(input_reg, 0x80000000u); | |
| 5326 __ j(not_equal, &done); | |
| 5327 // Check if the input was 0x8000000 (kMinInt). | |
| 5328 // If no, then we got an overflow and we deoptimize. | |
| 5329 ExternalReference min_int = ExternalReference::address_of_min_int(); | |
| 5330 __ movdbl(xmm_temp, Operand::StaticVariable(min_int)); | |
| 5331 __ ucomisd(xmm_temp, xmm0); | |
| 5332 DeoptimizeIf(not_equal, instr->environment()); | |
| 5333 DeoptimizeIf(parity_even, instr->environment()); // NaN. | |
| 5334 } else { | |
| 5335 UNREACHABLE(); | |
| 5336 } | |
| 5337 } else if (CpuFeatures::IsSupported(SSE2)) { | |
| 5338 CpuFeatureScope scope(masm(), SSE2); | |
| 5339 // Deoptimize if we don't have a heap number. | |
| 5340 __ RecordComment("Deferred TaggedToI: not a heap number"); | |
| 5341 DeoptimizeIf(not_equal, instr->environment()); | |
| 5342 | |
| 5343 XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); | |
| 5344 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | |
| 5345 __ cvttsd2si(input_reg, Operand(xmm0)); | |
| 5346 __ cvtsi2sd(xmm_temp, Operand(input_reg)); | |
| 5347 __ ucomisd(xmm0, xmm_temp); | |
| 5348 __ RecordComment("Deferred TaggedToI: lost precision"); | |
| 5349 DeoptimizeIf(not_equal, instr->environment()); | |
| 5350 __ RecordComment("Deferred TaggedToI: NaN"); | |
| 5351 DeoptimizeIf(parity_even, instr->environment()); // NaN. | |
| 5352 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 5353 __ test(input_reg, Operand(input_reg)); | |
| 5354 __ j(not_zero, &done); | |
| 5355 __ movmskpd(input_reg, xmm0); | |
| 5356 __ and_(input_reg, 1); | |
| 5357 __ RecordComment("Deferred TaggedToI: minus zero"); | |
| 5358 DeoptimizeIf(not_zero, instr->environment()); | |
| 5359 } | |
| 5360 } else { | 5299 } else { |
| 5361 UNREACHABLE(); | 5300 Label bailout; |
| 5301 XMMRegister scratch = (instr->temp() != NULL) |
| 5302 ? ToDoubleRegister(instr->temp()) |
| 5303 : no_xmm_reg; |
| 5304 __ TaggedToI(input_reg, input_reg, scratch, |
| 5305 instr->hydrogen()->GetMinusZeroMode(), &bailout); |
| 5306 __ jmp(done); |
| 5307 __ bind(&bailout); |
| 5308 DeoptimizeIf(no_condition, instr->environment()); |
| 5362 } | 5309 } |
| 5363 __ bind(&done); | |
| 5364 } | 5310 } |
| 5365 | 5311 |
| 5366 | 5312 |
| 5367 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { | 5313 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
| 5368 class DeferredTaggedToI V8_FINAL : public LDeferredCode { | 5314 class DeferredTaggedToI V8_FINAL : public LDeferredCode { |
| 5369 public: | 5315 public: |
| 5370 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) | 5316 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
| 5371 : LDeferredCode(codegen), instr_(instr) { } | 5317 : LDeferredCode(codegen), instr_(instr) { } |
| 5372 virtual void Generate() V8_OVERRIDE { | 5318 virtual void Generate() V8_OVERRIDE { |
| 5373 codegen()->DoDeferredTaggedToI(instr_); | 5319 codegen()->DoDeferredTaggedToI(instr_, done()); |
| 5374 } | 5320 } |
| 5375 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } | 5321 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
| 5376 private: | 5322 private: |
| 5377 LTaggedToI* instr_; | 5323 LTaggedToI* instr_; |
| 5378 }; | 5324 }; |
| 5379 | 5325 |
| 5380 LOperand* input = instr->value(); | 5326 LOperand* input = instr->value(); |
| 5381 ASSERT(input->IsRegister()); | 5327 ASSERT(input->IsRegister()); |
| 5382 Register input_reg = ToRegister(input); | 5328 Register input_reg = ToRegister(input); |
| 5383 ASSERT(input_reg.is(ToRegister(instr->result()))); | 5329 ASSERT(input_reg.is(ToRegister(instr->result()))); |
| 5384 | 5330 |
| 5385 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); | 5331 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); |
| 5386 | 5332 |
| 5387 __ JumpIfNotSmi(input_reg, deferred->entry()); | 5333 __ JumpIfNotSmi(input_reg, deferred->entry()); |
| 5388 __ SmiUntag(input_reg); | 5334 __ SmiUntag(input_reg); |
| 5389 __ bind(deferred->exit()); | 5335 __ bind(deferred->exit()); |
| 5390 } | 5336 } |
| 5391 | 5337 |
| 5392 | 5338 |
| 5393 void LCodeGen::DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr) { | |
| 5394 Label done, heap_number; | |
| 5395 Register result_reg = ToRegister(instr->result()); | |
| 5396 Register input_reg = ToRegister(instr->value()); | |
| 5397 | |
| 5398 // Heap number map check. | |
| 5399 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | |
| 5400 factory()->heap_number_map()); | |
| 5401 if (instr->truncating()) { | |
| 5402 __ j(equal, &heap_number, Label::kNear); | |
| 5403 // Check for undefined. Undefined is converted to zero for truncating | |
| 5404 // conversions. | |
| 5405 __ cmp(input_reg, factory()->undefined_value()); | |
| 5406 __ RecordComment("Deferred TaggedToI: cannot truncate"); | |
| 5407 DeoptimizeIf(not_equal, instr->environment()); | |
| 5408 __ xor_(result_reg, result_reg); | |
| 5409 __ jmp(&done, Label::kFar); | |
| 5410 __ bind(&heap_number); | |
| 5411 } else { | |
| 5412 // Deoptimize if we don't have a heap number. | |
| 5413 DeoptimizeIf(not_equal, instr->environment()); | |
| 5414 } | |
| 5415 | |
| 5416 // Surprisingly, all of this crazy bit manipulation is considerably | |
| 5417 // faster than using the built-in x86 CPU conversion functions (about 6x). | |
| 5418 Label right_exponent, adjust_bias, zero_result; | |
| 5419 Register scratch = ToRegister(instr->scratch()); | |
| 5420 Register scratch2 = ToRegister(instr->scratch2()); | |
| 5421 // Get exponent word. | |
| 5422 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | |
| 5423 // Get exponent alone in scratch2. | |
| 5424 __ mov(scratch2, scratch); | |
| 5425 __ and_(scratch2, HeapNumber::kExponentMask); | |
| 5426 __ shr(scratch2, HeapNumber::kExponentShift); | |
| 5427 if (instr->truncating()) { | |
| 5428 __ j(zero, &zero_result); | |
| 5429 } else { | |
| 5430 __ j(not_zero, &adjust_bias); | |
| 5431 __ test(scratch, Immediate(HeapNumber::kMantissaMask)); | |
| 5432 DeoptimizeIf(not_zero, instr->environment()); | |
| 5433 __ cmp(FieldOperand(input_reg, HeapNumber::kMantissaOffset), Immediate(0)); | |
| 5434 DeoptimizeIf(not_equal, instr->environment()); | |
| 5435 __ bind(&adjust_bias); | |
| 5436 } | |
| 5437 __ sub(scratch2, Immediate(HeapNumber::kExponentBias)); | |
| 5438 if (!instr->truncating()) { | |
| 5439 DeoptimizeIf(negative, instr->environment()); | |
| 5440 } else { | |
| 5441 __ j(negative, &zero_result); | |
| 5442 } | |
| 5443 | |
| 5444 // Get the second half of the double. For some exponents we don't | |
| 5445 // actually need this because the bits get shifted out again, but | |
| 5446 // it's probably slower to test than just to do it. | |
| 5447 Register scratch3 = ToRegister(instr->scratch3()); | |
| 5448 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); | |
| 5449 __ xor_(result_reg, result_reg); | |
| 5450 | |
| 5451 const uint32_t non_int32_exponent = 31; | |
| 5452 __ cmp(scratch2, Immediate(non_int32_exponent)); | |
| 5453 // If we have a match of the int32 exponent then skip some logic. | |
| 5454 __ j(equal, &right_exponent, Label::kNear); | |
| 5455 // If the number doesn't find in an int32, deopt. | |
| 5456 DeoptimizeIf(greater, instr->environment()); | |
| 5457 | |
| 5458 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent | |
| 5459 // < 31. | |
| 5460 __ mov(result_reg, Immediate(31)); | |
| 5461 __ sub(result_reg, scratch2); | |
| 5462 | |
| 5463 __ bind(&right_exponent); | |
| 5464 | |
| 5465 // Save off exponent for negative check later. | |
| 5466 __ mov(scratch2, scratch); | |
| 5467 | |
| 5468 // Here result_reg is the shift, scratch is the exponent word. | |
| 5469 // Get the top bits of the mantissa. | |
| 5470 __ and_(scratch, HeapNumber::kMantissaMask); | |
| 5471 // Put back the implicit 1. | |
| 5472 __ or_(scratch, 1 << HeapNumber::kExponentShift); | |
| 5473 // Shift up the mantissa bits to take up the space the exponent used to | |
| 5474 // take. We have kExponentShift + 1 significant bits int he low end of the | |
| 5475 // word. Shift them to the top bits. | |
| 5476 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; | |
| 5477 __ shl(scratch, shift_distance); | |
| 5478 if (!instr->truncating()) { | |
| 5479 // If not truncating, a non-zero value in the bottom 22 bits means a | |
| 5480 // non-integral value --> trigger a deopt. | |
| 5481 __ test(scratch3, Immediate((1 << (32 - shift_distance)) - 1)); | |
| 5482 DeoptimizeIf(not_equal, instr->environment()); | |
| 5483 } | |
| 5484 // Shift down 22 bits to get the most significant 10 bits or the low | |
| 5485 // mantissa word. | |
| 5486 __ shr(scratch3, 32 - shift_distance); | |
| 5487 __ or_(scratch3, scratch); | |
| 5488 if (!instr->truncating()) { | |
| 5489 // If truncating, a non-zero value in the bits that will be shifted away | |
| 5490 // when adjusting the exponent means rounding --> deopt. | |
| 5491 __ mov(scratch, 0x1); | |
| 5492 ASSERT(result_reg.is(ecx)); | |
| 5493 __ shl_cl(scratch); | |
| 5494 __ dec(scratch); | |
| 5495 __ test(scratch3, scratch); | |
| 5496 DeoptimizeIf(not_equal, instr->environment()); | |
| 5497 } | |
| 5498 // Move down according to the exponent. | |
| 5499 ASSERT(result_reg.is(ecx)); | |
| 5500 __ shr_cl(scratch3); | |
| 5501 // Now the unsigned 32-bit answer is in scratch3. We need to move it to | |
| 5502 // result_reg and we may need to fix the sign. | |
| 5503 Label negative_result; | |
| 5504 __ xor_(result_reg, result_reg); | |
| 5505 __ cmp(scratch2, result_reg); | |
| 5506 __ j(less, &negative_result, Label::kNear); | |
| 5507 __ cmp(scratch3, result_reg); | |
| 5508 __ mov(result_reg, scratch3); | |
| 5509 // If the result is > MAX_INT, result doesn't fit in signed 32-bit --> deopt. | |
| 5510 DeoptimizeIf(less, instr->environment()); | |
| 5511 __ jmp(&done, Label::kNear); | |
| 5512 __ bind(&zero_result); | |
| 5513 __ xor_(result_reg, result_reg); | |
| 5514 __ jmp(&done, Label::kNear); | |
| 5515 __ bind(&negative_result); | |
| 5516 __ sub(result_reg, scratch3); | |
| 5517 if (!instr->truncating()) { | |
| 5518 // -0.0 triggers a deopt. | |
| 5519 DeoptimizeIf(zero, instr->environment()); | |
| 5520 } | |
| 5521 // If the negative subtraction overflows into a positive number, there was an | |
| 5522 // overflow --> deopt. | |
| 5523 DeoptimizeIf(positive, instr->environment()); | |
| 5524 __ bind(&done); | |
| 5525 } | |
| 5526 | |
| 5527 | |
| 5528 void LCodeGen::DoTaggedToINoSSE2(LTaggedToINoSSE2* instr) { | |
| 5529 class DeferredTaggedToINoSSE2 V8_FINAL : public LDeferredCode { | |
| 5530 public: | |
| 5531 DeferredTaggedToINoSSE2(LCodeGen* codegen, LTaggedToINoSSE2* instr) | |
| 5532 : LDeferredCode(codegen), instr_(instr) { } | |
| 5533 virtual void Generate() V8_OVERRIDE { | |
| 5534 codegen()->DoDeferredTaggedToINoSSE2(instr_); | |
| 5535 } | |
| 5536 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } | |
| 5537 private: | |
| 5538 LTaggedToINoSSE2* instr_; | |
| 5539 }; | |
| 5540 | |
| 5541 LOperand* input = instr->value(); | |
| 5542 ASSERT(input->IsRegister()); | |
| 5543 Register input_reg = ToRegister(input); | |
| 5544 ASSERT(input_reg.is(ToRegister(instr->result()))); | |
| 5545 | |
| 5546 DeferredTaggedToINoSSE2* deferred = | |
| 5547 new(zone()) DeferredTaggedToINoSSE2(this, instr); | |
| 5548 | |
| 5549 // Smi check. | |
| 5550 __ JumpIfNotSmi(input_reg, deferred->entry()); | |
| 5551 __ SmiUntag(input_reg); // Untag smi. | |
| 5552 __ bind(deferred->exit()); | |
| 5553 } | |
| 5554 | |
| 5555 | |
| 5556 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { | 5339 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
| 5557 LOperand* input = instr->value(); | 5340 LOperand* input = instr->value(); |
| 5558 ASSERT(input->IsRegister()); | 5341 ASSERT(input->IsRegister()); |
| 5559 LOperand* temp = instr->temp(); | 5342 LOperand* temp = instr->temp(); |
| 5560 ASSERT(temp == NULL || temp->IsRegister()); | 5343 ASSERT(temp == NULL || temp->IsRegister()); |
| 5561 LOperand* result = instr->result(); | 5344 LOperand* result = instr->result(); |
| 5562 ASSERT(result->IsDoubleRegister()); | 5345 ASSERT(result->IsDoubleRegister()); |
| 5563 | 5346 |
| 5564 Register input_reg = ToRegister(input); | 5347 Register input_reg = ToRegister(input); |
| 5565 bool deoptimize_on_minus_zero = | 5348 bool deoptimize_on_minus_zero = |
| (...skipping 26 matching lines...) Expand all Loading... |
| 5592 } | 5375 } |
| 5593 | 5376 |
| 5594 | 5377 |
| 5595 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 5378 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 5596 LOperand* input = instr->value(); | 5379 LOperand* input = instr->value(); |
| 5597 ASSERT(input->IsDoubleRegister()); | 5380 ASSERT(input->IsDoubleRegister()); |
| 5598 LOperand* result = instr->result(); | 5381 LOperand* result = instr->result(); |
| 5599 ASSERT(result->IsRegister()); | 5382 ASSERT(result->IsRegister()); |
| 5600 Register result_reg = ToRegister(result); | 5383 Register result_reg = ToRegister(result); |
| 5601 | 5384 |
| 5602 Label done; | 5385 if (instr->truncating()) { |
| 5603 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { | 5386 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
| 5604 CpuFeatureScope scope(masm(), SSE2); | 5387 CpuFeatureScope scope(masm(), SSE2); |
| 5605 | 5388 XMMRegister input_reg = ToDoubleRegister(input); |
| 5606 XMMRegister input_reg = ToDoubleRegister(input); | 5389 __ TruncateDoubleToI(result_reg, input_reg); |
| 5607 | |
| 5608 __ cvttsd2si(result_reg, Operand(input_reg)); | |
| 5609 | |
| 5610 if (instr->truncating()) { | |
| 5611 // Performs a truncating conversion of a floating point number as used by | |
| 5612 // the JS bitwise operations. | |
| 5613 Label fast_case_succeeded; | |
| 5614 __ cmp(result_reg, 0x80000000u); | |
| 5615 __ j(not_equal, &fast_case_succeeded); | |
| 5616 __ sub(esp, Immediate(kDoubleSize)); | |
| 5617 __ movdbl(MemOperand(esp, 0), input_reg); | |
| 5618 DoubleToIStub stub(esp, result_reg, 0, true); | |
| 5619 __ call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET); | |
| 5620 __ add(esp, Immediate(kDoubleSize)); | |
| 5621 __ bind(&fast_case_succeeded); | |
| 5622 } else { | 5390 } else { |
| 5623 __ cvtsi2sd(xmm0, Operand(result_reg)); | 5391 X87Register input_reg = ToX87Register(input); |
| 5624 __ ucomisd(xmm0, input_reg); | 5392 X87Fxch(input_reg); |
| 5625 DeoptimizeIf(not_equal, instr->environment()); | 5393 __ TruncateX87TOSToI(result_reg); |
| 5626 DeoptimizeIf(parity_even, instr->environment()); // NaN. | |
| 5627 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 5628 // The integer converted back is equal to the original. We | |
| 5629 // only have to test if we got -0 as an input. | |
| 5630 __ test(result_reg, Operand(result_reg)); | |
| 5631 __ j(not_zero, &done, Label::kNear); | |
| 5632 __ movmskpd(result_reg, input_reg); | |
| 5633 // Bit 0 contains the sign of the double in input_reg. | |
| 5634 // If input was positive, we are ok and return 0, otherwise | |
| 5635 // deoptimize. | |
| 5636 __ and_(result_reg, 1); | |
| 5637 DeoptimizeIf(not_zero, instr->environment()); | |
| 5638 } | |
| 5639 __ bind(&done); | |
| 5640 } | 5394 } |
| 5641 } else { | 5395 } else { |
| 5642 X87Register input_reg = ToX87Register(input); | 5396 Label bailout, done; |
| 5643 __ push(result_reg); | 5397 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
| 5644 X87Mov(Operand(esp, 0), input_reg, kX87IntOperand); | 5398 CpuFeatureScope scope(masm(), SSE2); |
| 5645 if (instr->truncating()) { | 5399 XMMRegister input_reg = ToDoubleRegister(input); |
| 5646 __ pop(result_reg); | 5400 __ DoubleToI(result_reg, input_reg, xmm0, |
| 5401 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear); |
| 5647 } else { | 5402 } else { |
| 5403 X87Register input_reg = ToX87Register(input); |
| 5648 X87Fxch(input_reg); | 5404 X87Fxch(input_reg); |
| 5649 __ fld(0); | 5405 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(), |
| 5650 __ fild_s(Operand(esp, 0)); | 5406 &bailout, Label::kNear); |
| 5651 __ pop(result_reg); | |
| 5652 __ FCmp(); | |
| 5653 DeoptimizeIf(not_equal, instr->environment()); | |
| 5654 DeoptimizeIf(parity_even, instr->environment()); // NaN. | |
| 5655 } | 5407 } |
| 5656 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 5408 __ jmp(&done, Label::kNear); |
| 5657 __ test(result_reg, Operand(result_reg)); | 5409 __ bind(&bailout); |
| 5658 __ j(not_zero, &done, Label::kNear); | 5410 DeoptimizeIf(no_condition, instr->environment()); |
| 5659 // To check for minus zero, we load the value again as float, and check | 5411 __ bind(&done); |
| 5660 // if that is still 0. | |
| 5661 X87Fxch(input_reg); | |
| 5662 __ push(result_reg); | |
| 5663 __ fst_s(Operand(esp, 0)); | |
| 5664 __ pop(result_reg); | |
| 5665 __ test(result_reg, Operand(result_reg)); | |
| 5666 DeoptimizeIf(not_zero, instr->environment()); | |
| 5667 __ bind(&done); | |
| 5668 } | |
| 5669 } | 5412 } |
| 5670 } | 5413 } |
| 5671 | 5414 |
| 5672 | 5415 |
| 5673 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { | 5416 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { |
| 5674 LOperand* input = instr->value(); | 5417 LOperand* input = instr->value(); |
| 5675 ASSERT(input->IsDoubleRegister()); | 5418 ASSERT(input->IsDoubleRegister()); |
| 5676 LOperand* result = instr->result(); | 5419 LOperand* result = instr->result(); |
| 5677 ASSERT(result->IsRegister()); | 5420 ASSERT(result->IsRegister()); |
| 5678 Register result_reg = ToRegister(result); | 5421 Register result_reg = ToRegister(result); |
| 5679 | 5422 |
| 5680 Label done; | 5423 Label bailout, done; |
| 5681 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { | 5424 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
| 5682 CpuFeatureScope scope(masm(), SSE2); | 5425 CpuFeatureScope scope(masm(), SSE2); |
| 5683 | |
| 5684 XMMRegister input_reg = ToDoubleRegister(input); | 5426 XMMRegister input_reg = ToDoubleRegister(input); |
| 5685 | 5427 __ DoubleToI(result_reg, input_reg, xmm0, |
| 5686 __ cvttsd2si(result_reg, Operand(input_reg)); | 5428 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear); |
| 5687 __ cvtsi2sd(xmm0, Operand(result_reg)); | |
| 5688 __ ucomisd(xmm0, input_reg); | |
| 5689 DeoptimizeIf(not_equal, instr->environment()); | |
| 5690 DeoptimizeIf(parity_even, instr->environment()); // NaN. | |
| 5691 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 5692 // The integer converted back is equal to the original. We | |
| 5693 // only have to test if we got -0 as an input. | |
| 5694 __ test(result_reg, Operand(result_reg)); | |
| 5695 __ j(not_zero, &done, Label::kNear); | |
| 5696 __ movmskpd(result_reg, input_reg); | |
| 5697 // Bit 0 contains the sign of the double in input_reg. | |
| 5698 // If input was positive, we are ok and return 0, otherwise | |
| 5699 // deoptimize. | |
| 5700 __ and_(result_reg, 1); | |
| 5701 DeoptimizeIf(not_zero, instr->environment()); | |
| 5702 __ bind(&done); | |
| 5703 } | |
| 5704 } else { | 5429 } else { |
| 5705 X87Register input_reg = ToX87Register(input); | 5430 X87Register input_reg = ToX87Register(input); |
| 5706 X87Fxch(input_reg); | 5431 X87Fxch(input_reg); |
| 5707 __ push(result_reg); | 5432 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(), |
| 5708 X87Mov(Operand(esp, 0), input_reg, kX87IntOperand); | 5433 &bailout, Label::kNear); |
| 5709 __ fld(0); | 5434 } |
| 5710 __ fild_s(Operand(esp, 0)); | 5435 __ jmp(&done, Label::kNear); |
| 5711 __ pop(result_reg); | 5436 __ bind(&bailout); |
| 5712 __ FCmp(); | 5437 DeoptimizeIf(no_condition, instr->environment()); |
| 5713 DeoptimizeIf(not_equal, instr->environment()); | 5438 __ bind(&done); |
| 5714 DeoptimizeIf(parity_even, instr->environment()); // NaN. | |
| 5715 | 5439 |
| 5716 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 5717 __ test(result_reg, Operand(result_reg)); | |
| 5718 __ j(not_zero, &done, Label::kNear); | |
| 5719 // To check for minus zero, we load the value again as float, and check | |
| 5720 // if that is still 0. | |
| 5721 __ push(result_reg); | |
| 5722 __ fst_s(Operand(esp, 0)); | |
| 5723 __ pop(result_reg); | |
| 5724 __ test(result_reg, Operand(result_reg)); | |
| 5725 DeoptimizeIf(not_zero, instr->environment()); | |
| 5726 __ bind(&done); | |
| 5727 } | |
| 5728 } | |
| 5729 __ SmiTag(result_reg); | 5440 __ SmiTag(result_reg); |
| 5730 DeoptimizeIf(overflow, instr->environment()); | 5441 DeoptimizeIf(overflow, instr->environment()); |
| 5731 } | 5442 } |
| 5732 | 5443 |
| 5733 | 5444 |
| 5734 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 5445 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 5735 LOperand* input = instr->value(); | 5446 LOperand* input = instr->value(); |
| 5736 __ test(ToOperand(input), Immediate(kSmiTagMask)); | 5447 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 5737 DeoptimizeIf(not_zero, instr->environment()); | 5448 DeoptimizeIf(not_zero, instr->environment()); |
| 5738 } | 5449 } |
| (...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6550 FixedArray::kHeaderSize - kPointerSize)); | 6261 FixedArray::kHeaderSize - kPointerSize)); |
| 6551 __ bind(&done); | 6262 __ bind(&done); |
| 6552 } | 6263 } |
| 6553 | 6264 |
| 6554 | 6265 |
| 6555 #undef __ | 6266 #undef __ |
| 6556 | 6267 |
| 6557 } } // namespace v8::internal | 6268 } } // namespace v8::internal |
| 6558 | 6269 |
| 6559 #endif // V8_TARGET_ARCH_IA32 | 6270 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |