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

Side by Side Diff: src/arm/code-stubs-arm.cc

Issue 8840008: Port Math.pow inlining to ARM. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years 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
« no previous file with comments | « no previous file | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 3437 matching lines...) Expand 10 before | Expand all | Expand 10 after
3448 } 3448 }
3449 } 3449 }
3450 3450
3451 3451
3452 void StackCheckStub::Generate(MacroAssembler* masm) { 3452 void StackCheckStub::Generate(MacroAssembler* masm) {
3453 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 3453 __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
3454 } 3454 }
3455 3455
3456 3456
3457 void MathPowStub::Generate(MacroAssembler* masm) { 3457 void MathPowStub::Generate(MacroAssembler* masm) {
3458 Label call_runtime; 3458 CpuFeatures::Scope vfp3_scope(VFP3);
3459 const Register base = r1;
3460 const Register exponent = r2;
3461 const Register heapnumbermap = r5;
3462 const Register heapnumber = r0;
3463 const DoubleRegister double_base = d1;
3464 const DoubleRegister double_exponent = d2;
3465 const DoubleRegister double_result = d3;
3466 const DoubleRegister double_scratch = d0;
3467 const SwVfpRegister single_scratch = s0;
3468 const Register scratch = r9;
3469 const Register scratch2 = r7;
3459 3470
3460 if (CpuFeatures::IsSupported(VFP3)) { 3471 Label call_runtime, done, exponent_not_smi, int_exponent;
3461 CpuFeatures::Scope scope(VFP3); 3472 if (exponent_type_ == ON_STACK) {
3462 3473 Label base_is_smi, unpack_exponent;
3463 Label base_not_smi; 3474 // The exponent and base are supplied as arguments on the stack.
3464 Label exponent_not_smi; 3475 // This can only happen if the stub is called from non-optimized code.
3465 Label convert_exponent; 3476 // Load input parameters from stack to double registers.
3466
3467 const Register base = r0;
3468 const Register exponent = r1;
3469 const Register heapnumbermap = r5;
3470 const Register heapnumber = r6;
3471 const DoubleRegister double_base = d0;
3472 const DoubleRegister double_exponent = d1;
3473 const DoubleRegister double_result = d2;
3474 const SwVfpRegister single_scratch = s0;
3475 const Register scratch = r9;
3476 const Register scratch2 = r7;
3477
3478 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
3479 __ ldr(base, MemOperand(sp, 1 * kPointerSize)); 3477 __ ldr(base, MemOperand(sp, 1 * kPointerSize));
3480 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize)); 3478 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize));
3481 3479
3482 // Convert base to double value and store it in d0. 3480 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
3483 __ JumpIfNotSmi(base, &base_not_smi); 3481
3484 // Base is a Smi. Untag and convert it. 3482 __ JumpIfSmi(base, &base_is_smi);
3483 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
3484 __ cmp(scratch, heapnumbermap);
3485 __ b(ne, &call_runtime);
3486
3487 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
3488 __ jmp(&unpack_exponent);
3489
3490 __ bind(&base_is_smi);
3485 __ SmiUntag(base); 3491 __ SmiUntag(base);
3486 __ vmov(single_scratch, base); 3492 __ vmov(single_scratch, base);
3487 __ vcvt_f64_s32(double_base, single_scratch); 3493 __ vcvt_f64_s32(double_base, single_scratch);
3488 __ b(&convert_exponent); 3494 __ bind(&unpack_exponent);
3489 3495
3490 __ bind(&base_not_smi);
3491 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
3492 __ cmp(scratch, heapnumbermap);
3493 __ b(ne, &call_runtime);
3494 // Base is a heapnumber. Load it into double register.
3495 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
3496
3497 __ bind(&convert_exponent);
3498 __ JumpIfNotSmi(exponent, &exponent_not_smi); 3496 __ JumpIfNotSmi(exponent, &exponent_not_smi);
3499 __ SmiUntag(exponent); 3497 __ SmiUntag(exponent);
3500 3498 __ jmp(&int_exponent);
3501 // The base is in a double register and the exponent is
3502 // an untagged smi. Allocate a heap number and call a
3503 // C function for integer exponents. The register containing
3504 // the heap number is callee-saved.
3505 __ AllocateHeapNumber(heapnumber,
3506 scratch,
3507 scratch2,
3508 heapnumbermap,
3509 &call_runtime);
3510 __ push(lr);
3511 __ PrepareCallCFunction(1, 1, scratch);
3512 __ SetCallCDoubleArguments(double_base, exponent);
3513 {
3514 AllowExternalCallThatCantCauseGC scope(masm);
3515 __ CallCFunction(
3516 ExternalReference::power_double_int_function(masm->isolate()),
3517 1, 1);
3518 __ pop(lr);
3519 __ GetCFunctionDoubleResult(double_result);
3520 }
3521 __ vstr(double_result,
3522 FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
3523 __ mov(r0, heapnumber);
3524 __ Ret(2 * kPointerSize);
3525 3499
3526 __ bind(&exponent_not_smi); 3500 __ bind(&exponent_not_smi);
3527 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); 3501 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
3528 __ cmp(scratch, heapnumbermap); 3502 __ cmp(scratch, heapnumbermap);
3529 __ b(ne, &call_runtime); 3503 __ b(ne, &call_runtime);
3530 // Exponent is a heapnumber. Load it into double register.
3531 __ vldr(double_exponent, 3504 __ vldr(double_exponent,
3532 FieldMemOperand(exponent, HeapNumber::kValueOffset)); 3505 FieldMemOperand(exponent, HeapNumber::kValueOffset));
3506 } else if (exponent_type_ == TAGGED) {
3507 // Base is already in double_base.
3508 __ JumpIfNotSmi(exponent, &exponent_not_smi);
3509 __ SmiUntag(exponent);
3510 __ jmp(&int_exponent);
3533 3511
3534 // The base and the exponent are in double registers. 3512 __ bind(&exponent_not_smi);
3535 // Allocate a heap number and call a C function for 3513 __ vldr(double_exponent,
3536 // double exponents. The register containing 3514 FieldMemOperand(exponent, HeapNumber::kValueOffset));
3537 // the heap number is callee-saved. 3515 }
3538 __ AllocateHeapNumber(heapnumber, 3516
3539 scratch, 3517 if (exponent_type_ != INTEGER) {
3540 scratch2, 3518 // Detect integer exponents stored as double.
3541 heapnumbermap, 3519 __ vcvt_u32_f64(single_scratch, double_exponent);
3542 &call_runtime); 3520 // We do not check for NaN or Infinity here because comparing numbers on
3521 // ARM correctly distinguishes NaNs. We end up calling the built-in.
3522 __ vcvt_f64_u32(double_scratch, single_scratch);
3523 __ VFPCompareAndSetFlags(double_scratch, double_exponent);
3524 __ vmov(exponent, single_scratch, eq);
3525 __ b(eq, &int_exponent);
3526
3527 if (exponent_type_ == ON_STACK) {
3528 // Detect square root case. Crankshaft detects constant +/-0.5 at
3529 // compile time and uses DoMathPowHalf instead. We then skip this check
3530 // for non-constant cases of +/-0.5 as these hardly occur.
3531 Label not_plus_half;
3532
3533 // Test for 0.5.
3534 __ vmov(double_scratch, 0.5);
3535 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
3536 __ b(ne, &not_plus_half);
3537
3538 // Calculates square root of base. Check for the special case of
3539 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
3540 __ vmov(double_scratch, -V8_INFINITY);
3541 __ VFPCompareAndSetFlags(double_base, double_scratch);
3542 __ vneg(double_result, double_scratch, eq);
3543 __ b(eq, &done);
3544
3545 // Add +0 to convert -0 to +0.
3546 __ vadd(double_scratch, double_base, kDoubleRegZero);
3547 __ vsqrt(double_result, double_scratch);
3548 __ jmp(&done);
3549
3550 __ bind(&not_plus_half);
3551 __ vmov(double_scratch, -0.5);
3552 __ VFPCompareAndSetFlags(double_exponent, double_scratch);
3553 __ b(ne, &call_runtime);
3554
3555 // Calculates square root of base. Check for the special case of
3556 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
3557 __ vmov(double_scratch, -V8_INFINITY);
3558 __ VFPCompareAndSetFlags(double_base, double_scratch);
3559 __ vmov(double_result, kDoubleRegZero, eq);
3560 __ b(eq, &done);
3561
3562 // Add +0 to convert -0 to +0.
3563 __ vadd(double_scratch, double_base, kDoubleRegZero);
3564 __ vmov(double_result, 1);
3565 __ vsqrt(double_scratch, double_scratch);
3566 __ vdiv(double_result, double_result, double_scratch);
3567 __ jmp(&done);
3568 }
3569
3543 __ push(lr); 3570 __ push(lr);
3544 __ PrepareCallCFunction(0, 2, scratch);
3545 __ SetCallCDoubleArguments(double_base, double_exponent);
3546 { 3571 {
3547 AllowExternalCallThatCantCauseGC scope(masm); 3572 AllowExternalCallThatCantCauseGC scope(masm);
3573 __ PrepareCallCFunction(0, 2, scratch);
3574 __ SetCallCDoubleArguments(double_base, double_exponent);
3548 __ CallCFunction( 3575 __ CallCFunction(
3549 ExternalReference::power_double_double_function(masm->isolate()), 3576 ExternalReference::power_double_double_function(masm->isolate()),
3550 0, 2); 3577 0, 2);
3551 __ pop(lr);
3552 __ GetCFunctionDoubleResult(double_result);
3553 } 3578 }
3579 __ pop(lr);
3580 __ GetCFunctionDoubleResult(double_result);
3581 __ jmp(&done);
3582 }
3583
3584 // Calculate power with integer exponent.
3585 __ bind(&int_exponent);
3586
3587 __ mov(scratch, exponent); // Back up exponent.
3588 __ vmov(double_scratch, double_base); // Back up base.
3589 __ vmov(double_result, 1.0);
3590
3591 // Get absolute value of exponent.
3592 __ cmp(scratch, Operand(0));
3593 __ mov(scratch2, Operand(0), LeaveCC, mi);
3594 __ sub(scratch, scratch2, scratch, LeaveCC, mi);
3595
3596 Label while_true;
3597 __ bind(&while_true);
3598 __ mov(scratch, Operand(scratch, ASR, 1), SetCC);
3599 __ vmul(double_result, double_result, double_scratch, cs);
3600 __ vmul(double_scratch, double_scratch, double_scratch, ne);
3601 __ b(ne, &while_true);
3602
3603 __ cmp(exponent, Operand(0));
3604 __ b(ge, &done);
3605 __ vmov(double_scratch, 1.0);
3606 __ vdiv(double_result, double_scratch, double_result);
3607 // Test whether result is zero. Bail out to check for subnormal result.
3608 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
3609 __ VFPCompareAndSetFlags(double_result, 0.0);
3610 __ b(ne, &done);
3611
3612 __ vmov(single_scratch, exponent);
3613 __ vcvt_f64_s32(double_exponent, single_scratch);
3614
3615 // Returning or bailing out.
3616 Counters* counters = masm->isolate()->counters();
3617 if (exponent_type_ == ON_STACK) {
3618 // The arguments are still on the stack.
3619 __ bind(&call_runtime);
3620 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3621
3622 // The stub is called from non-optimized code, which expects the result
3623 // as heap number in exponent.
3624 __ bind(&done);
3625 __ AllocateHeapNumber(
3626 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
3554 __ vstr(double_result, 3627 __ vstr(double_result,
3555 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); 3628 FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
3556 __ mov(r0, heapnumber); 3629 ASSERT(heapnumber.is(r0));
3630 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
3557 __ Ret(2 * kPointerSize); 3631 __ Ret(2 * kPointerSize);
3632 } else {
3633 __ bind(&done);
3634 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
3635 __ Ret();
3558 } 3636 }
3559
3560 __ bind(&call_runtime);
3561 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3562 } 3637 }
3563 3638
3564 3639
3565 bool CEntryStub::NeedsImmovableCode() { 3640 bool CEntryStub::NeedsImmovableCode() {
3566 return true; 3641 return true;
3567 } 3642 }
3568 3643
3569 3644
3570 bool CEntryStub::IsPregenerated() { 3645 bool CEntryStub::IsPregenerated() {
3571 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && 3646 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
(...skipping 3676 matching lines...) Expand 10 before | Expand all | Expand 10 after
7248 __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10, 7323 __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10,
7249 &slow_elements); 7324 &slow_elements);
7250 __ Ret(); 7325 __ Ret();
7251 } 7326 }
7252 7327
7253 #undef __ 7328 #undef __
7254 7329
7255 } } // namespace v8::internal 7330 } } // namespace v8::internal
7256 7331
7257 #endif // V8_TARGET_ARCH_ARM 7332 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « no previous file | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698