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

Side by Side Diff: src/x64/codegen-x64.cc

Issue 269004: X64: Convert doubles to int32 inline (without calling runtime).
Patch Set: Created 11 years, 2 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
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 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 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 // Input values must be either smi or heap number objects (fp values). 218 // Input values must be either smi or heap number objects (fp values).
219 // Requirements: 219 // Requirements:
220 // Register version: operands in registers lhs and rhs. 220 // Register version: operands in registers lhs and rhs.
221 // Stack version: operands on TOS+1 and TOS+2. 221 // Stack version: operands on TOS+1 and TOS+2.
222 // Returns operands as floating point numbers on fp stack. 222 // Returns operands as floating point numbers on fp stack.
223 static void LoadFloatOperands(MacroAssembler* masm); 223 static void LoadFloatOperands(MacroAssembler* masm);
224 static void LoadFloatOperands(MacroAssembler* masm, 224 static void LoadFloatOperands(MacroAssembler* masm,
225 Register lhs, 225 Register lhs,
226 Register rhs); 226 Register rhs);
227 227
228 // Code pattern for loading a floating point value and converting it 228 // Code pattern for loading a floating point argument and converting it
229 // to a 32 bit integer. Input value must be either a smi or a heap number 229 // to a 32 bit integer by truncating. Input value must be either a smi or
230 // object. 230 // a heap number object, otherwise the on_non_number label is jumped to.
231 // Returns operands as 32-bit sign extended integers in a general purpose 231 // Expects arguments in register src, and returns result in register dst.
232 // registers. 232 // Uses rcx and rax (src may not be either of these).
233 static void LoadInt32Operand(MacroAssembler* masm, 233 static void LoadInt32OperandSSE3(MacroAssembler* masm,
234 const Operand& src, 234 Register dst,
235 Register dst); 235 Register src,
236 Label* on_non_number);
237 static void LoadInt32OperandFPU(MacroAssembler* masm,
238 Register dst,
239 Register src,
240 Label* on_non_number);
236 241
237 // Test if operands are smi or number objects (fp). Requirements: 242 // Test if operands are smi or number objects (fp). Requirements:
238 // operand_1 in rax, operand_2 in rdx; falls through on float or smi 243 // operand_1 in rax, operand_2 in rdx; falls through on float or smi
239 // operands, jumps to the non_float label otherwise. 244 // operands, jumps to the non_float label otherwise.
240 static void CheckFloatOperands(MacroAssembler* masm, 245 static void CheckFloatOperands(MacroAssembler* masm,
241 Label* non_float); 246 Label* non_float);
242 247
243 // Allocate a heap number in new space with undefined value. 248 // Allocate a heap number in new space with undefined value.
244 // Returns tagged pointer in result, or jumps to need_gc if new space is full. 249 // Returns tagged pointer in result, or jumps to need_gc if new space is full.
245 static void AllocateHeapNumber(MacroAssembler* masm, 250 static void AllocateHeapNumber(MacroAssembler* masm,
(...skipping 7001 matching lines...) Expand 10 before | Expand all | Expand 10 after
7247 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 7252 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
7248 XMMRegister dst1, 7253 XMMRegister dst1,
7249 XMMRegister dst2) { 7254 XMMRegister dst2) {
7250 __ movq(kScratchRegister, Operand(rsp, 2 * kPointerSize)); 7255 __ movq(kScratchRegister, Operand(rsp, 2 * kPointerSize));
7251 LoadFloatOperand(masm, kScratchRegister, dst1); 7256 LoadFloatOperand(masm, kScratchRegister, dst1);
7252 __ movq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); 7257 __ movq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
7253 LoadFloatOperand(masm, kScratchRegister, dst2); 7258 LoadFloatOperand(masm, kScratchRegister, dst2);
7254 } 7259 }
7255 7260
7256 7261
7257 void FloatingPointHelper::LoadInt32Operand(MacroAssembler* masm, 7262 void FloatingPointHelper::LoadInt32OperandSSE3(MacroAssembler* masm,
7258 const Operand& src, 7263 Register dst,
7259 Register dst) { 7264 Register src,
7260 // TODO(X64): Convert number operands to int32 values. 7265 Label* on_non_number) {
7261 // Don't convert a Smi to a double first. 7266 ASSERT(!src.is(rax));
7262 UNIMPLEMENTED(); 7267 ASSERT(!src.is(rcx));
7268
7269 CpuFeatures::Scope scope(CpuFeatures::SSE3);
7270
7271 Label non_smi;
7272 Label done;
7273 Label non_smi_value;
7274
7275 __ JumpIfNotSmi(src, &non_smi);
7276 __ SmiToInteger32(dst, src);
7277 __ jmp(&done);
7278
7279 // Do a full conversion by operating on the double bits.
7280 __ bind(&non_smi_value);
7281 __ addq(rsp, Immediate(kPointerSize));
7282 __ fnclex();
7283 __ movq(src, FieldOperand(src, HeapNumber::kValueOffset));
7284 __ DoubleToInteger32(dst, src, rax);
7285 __ jmp(&done);
7286
7287 __ bind(&non_smi);
7288 // Check that we have a HeapNumber.
7289 __ CompareRoot(FieldOperand(src, HeapObject::kMapOffset),
7290 Heap::kHeapNumberMapRootIndex);
7291 __ j(not_equal, on_non_number);
7292
7293 // Try quick conversion, if the double holds a valid smi value.
7294
7295 __ fld_d(FieldOperand(src, HeapNumber::kValueOffset));
7296 __ subq(rsp, Immediate(kPointerSize));
7297 __ fisttp_s(Operand(rsp, 0 * kPointerSize));
7298 __ fnstsw_ax();
7299 __ testl(rax, Immediate(1));
7300 __ j(not_zero, &non_smi_value);
7301 __ pop(dst);
7302
7303 __ bind(&done);
7263 } 7304 }
7264 7305
7265 7306
7307 void FloatingPointHelper::LoadInt32OperandFPU(MacroAssembler* masm,
7308 Register dst,
7309 Register src,
7310 Label* on_non_number) {
7311 ASSERT(!src.is(rax));
7312 ASSERT(!src.is(rcx));
7313
7314 Label non_smi;
7315 Label done;
7316 Label non_smi_value;
7317
7318 __ JumpIfNotSmi(src, &non_smi);
7319 __ SmiToInteger32(dst, src);
7320 __ jmp(&done);
7321
7322 // Do a full conversion by operating on the double bits.
7323 __ bind(&non_smi_value);
7324 __ addq(rsp, Immediate(kPointerSize));
7325 __ movq(src, FieldOperand(src, HeapNumber::kValueOffset));
7326 __ DoubleToInteger32(dst, src, rax);
7327 __ jmp(&done);
7328
7329 __ bind(&non_smi);
7330 // Check that we have a HeapNumber.
7331 __ CompareRoot(FieldOperand(src, HeapObject::kMapOffset),
7332 Heap::kHeapNumberMapRootIndex);
7333 __ j(not_equal, on_non_number);
7334
7335 // Try quick conversion, if the double holds a valid smi value.
7336
7337 __ fld_d(FieldOperand(src, HeapNumber::kValueOffset));
7338 __ subq(rsp, Immediate(kPointerSize));
7339 __ fist_s(Operand(rsp, 0 * kPointerSize));
7340 __ fild_s(Operand(rsp, 0 * kPointerSize));
7341 __ fucompp();
7342 __ fnstsw_ax();
7343 if (CpuFeatures::IsSupported(CpuFeatures::SAHF)) {
7344 __ sahf();
7345 __ j(not_zero, &non_smi_value);
7346 __ j(parity_even, &non_smi_value);
7347 } else {
7348 __ and_(rax, Immediate(0x4400));
7349 __ cmpl(rax, Immediate(0x4000));
7350 __ j(not_equal, &non_smi_value);
7351 }
7352 __ pop(dst);
7353
7354 __ bind(&done);
7355 }
7356
7357
7358
7266 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm) { 7359 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm) {
7267 Label load_smi_1, load_smi_2, done_load_1, done; 7360 Label load_smi_1, load_smi_2, done_load_1, done;
7268 __ movq(kScratchRegister, Operand(rsp, 2 * kPointerSize)); 7361 __ movq(kScratchRegister, Operand(rsp, 2 * kPointerSize));
7269 __ JumpIfSmi(kScratchRegister, &load_smi_1); 7362 __ JumpIfSmi(kScratchRegister, &load_smi_1);
7270 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); 7363 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
7271 __ bind(&done_load_1); 7364 __ bind(&done_load_1);
7272 7365
7273 __ movq(kScratchRegister, Operand(rsp, 1 * kPointerSize)); 7366 __ movq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
7274 __ JumpIfSmi(kScratchRegister, &load_smi_2); 7367 __ JumpIfSmi(kScratchRegister, &load_smi_2);
7275 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); 7368 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
7395 __ SmiAnd(rax, rax, rbx); 7488 __ SmiAnd(rax, rax, rbx);
7396 break; 7489 break;
7397 7490
7398 case Token::BIT_XOR: 7491 case Token::BIT_XOR:
7399 __ SmiXor(rax, rax, rbx); 7492 __ SmiXor(rax, rax, rbx);
7400 break; 7493 break;
7401 7494
7402 case Token::SHL: 7495 case Token::SHL:
7403 case Token::SHR: 7496 case Token::SHR:
7404 case Token::SAR: 7497 case Token::SAR:
7405 // Move the second operand into register ecx.
7406 __ movl(rcx, rbx);
7407 // Perform the operation. 7498 // Perform the operation.
7408 switch (op_) { 7499 switch (op_) {
7409 case Token::SAR: 7500 case Token::SAR:
7410 __ SmiShiftArithmeticRight(rax, rax, rbx); 7501 __ SmiShiftArithmeticRight(rax, rax, rbx);
7411 break; 7502 break;
7412 case Token::SHR: 7503 case Token::SHR:
7413 __ SmiShiftLogicalRight(rax, rax, rbx, slow); 7504 __ SmiShiftLogicalRight(rax, rax, rbx, slow);
7414 break; 7505 break;
7415 case Token::SHL: 7506 case Token::SHL:
7416 __ SmiShiftLeft(rax, rax, rbx, slow); 7507 __ SmiShiftLeft(rax, rax, rbx, slow);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
7492 case Token::MOD: { 7583 case Token::MOD: {
7493 // For MOD we go directly to runtime in the non-smi case. 7584 // For MOD we go directly to runtime in the non-smi case.
7494 break; 7585 break;
7495 } 7586 }
7496 case Token::BIT_OR: 7587 case Token::BIT_OR:
7497 case Token::BIT_AND: 7588 case Token::BIT_AND:
7498 case Token::BIT_XOR: 7589 case Token::BIT_XOR:
7499 case Token::SAR: 7590 case Token::SAR:
7500 case Token::SHL: 7591 case Token::SHL:
7501 case Token::SHR: { 7592 case Token::SHR: {
7502 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime); 7593 Label skip_allocation, non_smi_result, operand_conversion_failure;
Lasse Reichstein 2009/10/07 16:54:24 I'm considering using CheckFloatOperands first, to
7503 // TODO(X64): Don't convert a Smi to float and then back to int32 7594 // Arguments in rax/rsp[1] and rdx/rsp[0].
7504 // afterwards. 7595 // Move rhs to rbx, since conversion uses rax to read FPU status word.
7505 FloatingPointHelper::LoadFloatOperands(masm); 7596 __ movq(rbx, rax);
7597 if (use_sse3_) {
7598 FloatingPointHelper::LoadInt32OperandSSE3(masm,
7599 rdx,
7600 rdx,
7601 &operand_conversion_failure);
7602 FloatingPointHelper::LoadInt32OperandSSE3(masm,
7603 rcx,
7604 rbx,
7605 &operand_conversion_failure);
7606 } else {
7607 FloatingPointHelper::LoadInt32OperandFPU(masm,
7608 rdx,
7609 rdx,
7610 &operand_conversion_failure);
7611 FloatingPointHelper::LoadInt32OperandFPU(masm,
7612 rcx,
7613 rbx,
7614 &operand_conversion_failure);
7615 }
7616 // 32-bit values in rbx, rcx.
7506 7617
7507 Label skip_allocation, non_smi_result, operand_conversion_failure;
7508
7509 // Reserve space for converted numbers.
7510 __ subq(rsp, Immediate(2 * kPointerSize));
7511
7512 if (use_sse3_) {
7513 // Truncate the operands to 32-bit integers and check for
7514 // exceptions in doing so.
7515 CpuFeatures::Scope scope(CpuFeatures::SSE3);
7516 __ fisttp_s(Operand(rsp, 0 * kPointerSize));
7517 __ fisttp_s(Operand(rsp, 1 * kPointerSize));
7518 __ fnstsw_ax();
7519 __ testl(rax, Immediate(1));
7520 __ j(not_zero, &operand_conversion_failure);
7521 } else {
7522 // Check if right operand is int32.
7523 __ fist_s(Operand(rsp, 0 * kPointerSize));
7524 __ fild_s(Operand(rsp, 0 * kPointerSize));
7525 __ fucompp();
7526 __ fnstsw_ax();
7527 if (CpuFeatures::IsSupported(CpuFeatures::SAHF)) {
7528 __ sahf();
7529 __ j(not_zero, &operand_conversion_failure);
7530 __ j(parity_even, &operand_conversion_failure);
7531 } else {
7532 __ and_(rax, Immediate(0x4400));
7533 __ cmpl(rax, Immediate(0x4000));
7534 __ j(not_zero, &operand_conversion_failure);
7535 }
7536 // Check if left operand is int32.
7537 __ fist_s(Operand(rsp, 1 * kPointerSize));
7538 __ fild_s(Operand(rsp, 1 * kPointerSize));
7539 __ fucompp();
7540 __ fnstsw_ax();
7541 if (CpuFeatures::IsSupported(CpuFeatures::SAHF)) {
7542 __ sahf();
7543 __ j(not_zero, &operand_conversion_failure);
7544 __ j(parity_even, &operand_conversion_failure);
7545 } else {
7546 __ and_(rax, Immediate(0x4400));
7547 __ cmpl(rax, Immediate(0x4000));
7548 __ j(not_zero, &operand_conversion_failure);
7549 }
7550 }
7551
7552 // Get int32 operands and perform bitop.
7553 __ pop(rcx);
7554 __ pop(rax);
7555 switch (op_) { 7618 switch (op_) {
7556 case Token::BIT_OR: __ or_(rax, rcx); break; 7619 case Token::BIT_OR: __ orl(rdx, rcx); break;
7557 case Token::BIT_AND: __ and_(rax, rcx); break; 7620 case Token::BIT_AND: __ andl(rdx, rcx); break;
7558 case Token::BIT_XOR: __ xor_(rax, rcx); break; 7621 case Token::BIT_XOR: __ xorl(rdx, rcx); break;
7559 case Token::SAR: __ sarl(rax); break; 7622 case Token::SAR: __ sarl(rdx); break;
7560 case Token::SHL: __ shll(rax); break; 7623 case Token::SHL: __ shll(rdx); break;
7561 case Token::SHR: __ shrl(rax); break; 7624 case Token::SHR: __ shrl(rdx); break;
7562 default: UNREACHABLE(); 7625 default: UNREACHABLE();
7563 } 7626 }
7564 if (op_ == Token::SHR) { 7627 if (op_ == Token::SHR) {
7565 // Check if result is non-negative and fits in a smi. 7628 // Check if result is non-negative and fits in a smi.
7566 __ testl(rax, Immediate(0xc0000000)); 7629 __ testl(rdx, Immediate(0xc0000000));
7567 __ j(not_zero, &non_smi_result); 7630 __ j(not_zero, &non_smi_result);
7568 } else { 7631 } else {
7569 // Check if result fits in a smi. 7632 // Check if result fits in a smi.
7570 __ cmpl(rax, Immediate(0xc0000000)); 7633 __ cmpl(rdx, Immediate(0xc0000000));
7571 __ j(negative, &non_smi_result); 7634 __ j(negative, &non_smi_result);
7572 } 7635 }
7573 // Tag smi result and return. 7636 // Tag smi result and return.
7574 __ Integer32ToSmi(rax, rax); 7637 __ Integer32ToSmi(rax, rdx);
7575 __ ret(2 * kPointerSize); 7638 __ ret(2 * kPointerSize);
7576 7639
7577 // All ops except SHR return a signed int32 that we load in a HeapNumber. 7640 // All ops except SHR return a signed int32 that we load in a HeapNumber.
7578 if (op_ != Token::SHR) { 7641 if (op_ != Token::SHR) {
7579 __ bind(&non_smi_result); 7642 __ bind(&non_smi_result);
7580 // Allocate a heap number if needed. 7643 // Allocate a heap number if needed.
7581 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result 7644 __ movsxlq(rbx, rdx); // rbx: sign extended 32-bit result
7582 switch (mode_) { 7645 switch (mode_) {
7583 case OVERWRITE_LEFT: 7646 case OVERWRITE_LEFT:
7584 case OVERWRITE_RIGHT: 7647 case OVERWRITE_RIGHT:
7585 // If the operand was an object, we skip the 7648 // If the operand was an object, we skip the
7586 // allocation of a heap number. 7649 // allocation of a heap number.
7587 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? 7650 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
7588 1 * kPointerSize : 2 * kPointerSize)); 7651 1 * kPointerSize : 2 * kPointerSize));
7589 __ JumpIfNotSmi(rax, &skip_allocation); 7652 __ JumpIfNotSmi(rax, &skip_allocation);
7590 // Fall through! 7653 // Fall through!
7591 case NO_OVERWRITE: 7654 case NO_OVERWRITE:
7592 FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime, 7655 FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
7593 rcx, rax); 7656 rcx, rax);
7594 __ bind(&skip_allocation); 7657 __ bind(&skip_allocation);
7595 break; 7658 break;
7596 default: UNREACHABLE(); 7659 default: UNREACHABLE();
7597 } 7660 }
7598 // Store the result in the HeapNumber and return. 7661 // Store the result in the HeapNumber and return.
7599 __ movq(Operand(rsp, 1 * kPointerSize), rbx); 7662 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
7600 __ fild_s(Operand(rsp, 1 * kPointerSize)); 7663 __ fild_s(Operand(rsp, 1 * kPointerSize));
7601 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); 7664 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
7602 __ ret(2 * kPointerSize); 7665 __ ret(2 * kPointerSize);
7603 } 7666 }
7604 7667
7605 // Clear the FPU exception flag and reset the stack before calling 7668 // Fast-case operation failed, so call the runtime to perform the operatio n.
7606 // the runtime system.
7607 __ bind(&operand_conversion_failure); 7669 __ bind(&operand_conversion_failure);
7608 __ addq(rsp, Immediate(2 * kPointerSize));
7609 if (use_sse3_) {
7610 // If we've used the SSE3 instructions for truncating the
7611 // floating point values to integers and it failed, we have a
7612 // pending #IA exception. Clear it.
7613 __ fnclex();
7614 } else {
7615 // The non-SSE3 variant does early bailout if the right
7616 // operand isn't a 32-bit integer, so we may have a single
7617 // value on the FPU stack we need to get rid of.
7618 __ ffree(0);
7619 }
7620 7670
7621 // SHR should return uint32 - go to runtime for non-smi/negative result. 7671 // SHR should return uint32 - go to runtime for non-smi/negative result.
7622 if (op_ == Token::SHR) { 7672 if (op_ == Token::SHR) {
7623 __ bind(&non_smi_result); 7673 __ bind(&non_smi_result);
7624 } 7674 }
7625 __ movq(rax, Operand(rsp, 1 * kPointerSize)); 7675 __ movq(rax, Operand(rsp, 1 * kPointerSize));
7626 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 7676 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
7627 break; 7677 break;
7628 } 7678 }
7629 default: UNREACHABLE(); break; 7679 default: UNREACHABLE(); break;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
7675 int CompareStub::MinorKey() { 7725 int CompareStub::MinorKey() {
7676 // Encode the two parameters in a unique 16 bit value. 7726 // Encode the two parameters in a unique 16 bit value.
7677 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); 7727 ASSERT(static_cast<unsigned>(cc_) < (1 << 15));
7678 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); 7728 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0);
7679 } 7729 }
7680 7730
7681 7731
7682 #undef __ 7732 #undef __
7683 7733
7684 } } // namespace v8::internal 7734 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698