VirtualBox

Ignore:
Timestamp:
Aug 19, 2022 2:49:44 PM (2 years ago)
Author:
vboxsync
Message:

IPRT/nocrt: Split out the core of the pow() code into a common function and can be shared with powf and powl. bugref:10261

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/math/powcore.asm

    r96336 r96337  
    11; $Id$
    22;; @file
    3 ; IPRT - No-CRT pow - AMD64 & X86.
     3; IPRT - No-CRT common pow code - AMD64 & X86.
    44;
    55
     
    5252
    5353;;
    54 ; Compute the rdBase to the power of rdExp.
    55 ; @returns st(0) / xmm0
    56 ; @param    rdBase      [xSP + xCB*2] / xmm0
    57 ; @param    rdExp       [xSP + xCB*2 + RTLRD_CB] / xmm1
    58 RT_NOCRT_BEGINPROC pow
     54; Compute the st1 to the power of st0.
     55;
     56; @returns  st(0) = result
     57;           eax = what's being returned:
     58;               0 - Just a value.
     59;               1 - The rBase value. Caller may take steps to ensure it's exactly the same.
     60;               2 - The rExp value.  Caller may take steps to ensure it's exactly the same.
     61; @param    rBase/st1       The base.
     62; @param    rExp/st0        The exponent
     63; @param    fFxamBase/dx    The status flags after fxam(rBase).
     64; @param    enmType/ebx     The original parameter and return types:
     65;                               0 - 32-bit / float
     66;                               1 - 64-bit / double
     67;                               2 - 80-bit / long double
     68;
     69BEGINPROC rtNoCrtMathPowCore
    5970        push    xBP
    6071        SEH64_PUSH_xBP
     
    6475        SEH64_ALLOCATE_STACK 30h
    6576        SEH64_END_PROLOGUE
    66 
    67         ;
    68         ; Load rdBase into st1 and rdExp into st0.
    69         ;
    70 %ifdef RT_ARCH_AMD64
    71         movsd   [xBP - 10h], xmm0
    72         fld     qword [xBP - 10h]
    73         fxam
    74         fnstsw  ax
    75         mov     dx, ax                      ; dx=fxam(base)
    76 
    77         movsd   [xBP - 20h], xmm1
    78         fld     qword [xBP - 20h]
    79 %else
    80         fld     qword [xBP + xCB*2]
    81         fxam
    82         fnstsw  ax
    83         mov     dx, ax                      ; dx=fxam(base)
    84 
    85         fld     qword [xBP + xCB*2 + RTLRD_CB]
    86 %endif
    8777
    8878        ;
     
    212202
    213203.integer_exp_return:
    214         ffreep  st0                         ; drop the factor -> st0=result
     204        ffreep  st0                         ; drop the factor -> st0=result; no st1.
    215205        jmp     .return_val
    216206
     
    292282        ;
    293283.return_val:
    294 %ifdef RT_ARCH_AMD64
    295         fstp    qword [xBP - 10h]
    296         movsd   xmm0, [xBP - 10h]
    297 %endif
     284        xor     eax, eax
    298285.return:
    299286        leave
     
    334321.exp_zero:
    335322.return_plus_one:
    336 %ifdef RT_ARCH_AMD64
    337         movsd   xmm0, qword [.s_r64PlusOne xWrtRIP]
    338 %else
    339323        fld1
    340 %endif
    341324        jmp     .return_pop_pop_val
    342325
     
    429412        jnz     .return_base_value          ; Matching 8
    430413.return_plus_zero:                          ; Matching 9
    431 %ifdef RT_ARCH_AMD64
    432         movsd   xmm0, qword [.s_r64PlusZero xWrtRIP]
    433 %else
    434414        fldz
    435 %endif
    436415        jmp     .return_pop_pop_val
    437416
     
    458437        jz      .return_plus_zero           ; Matches 16 (exp not odd and < 0, base == -Inf)
    459438.return_minus_zero:                         ; Matches 15 (exp is odd and < 0, base == -Inf)
    460 %ifdef RT_ARCH_AMD64
    461         movsd   xmm0, qword [.s_r64MinusZero xWrtRIP]
    462 %else
    463439        fldz
    464440        fchs
    465 %endif
    466441        jmp     .return_pop_pop_val
    467442
     
    479454        ;
    480455.return_exp_nan:
    481 %ifdef RT_ARCH_AMD64
    482         movsd   xmm0, xmm1
    483 %else
    484456        fld     st0
    485 %endif
    486         jmp     .return_pop_pop_val
     457        mov     eax, 2                      ; return param 2
     458        jmp     .return_pop_pop_val_with_eax
    487459
    488460        ;
     
    492464.return_base_value:
    493465.base_nan:                  ; 5. Unless specified elsewhere, return NaN if any of the parameters are NaN.
    494 %ifdef RT_ARCH_AMD64
    495         ; xmm0 = base already
    496 %else
    497466        fld     st1
    498 %endif
     467        mov     eax, 1                      ; return param 1
     468        jmp     .return_pop_pop_val_with_eax
     469
     470        ;
     471        ; Pops the two values off the FPU stack and returns NaN.
     472        ;
     473.return_nan:
     474        fld     qword [.s_r64QNan xWrtRIP]
    499475        jmp     .return_pop_pop_val
    500476
    501477        ;
    502         ; Pops the two values off the FPU stack and returns NaN.
    503         ;
    504 .return_nan:
    505 %ifdef RT_ARCH_AMD64
    506         movsd   xmm0, qword [.s_r64QNan xWrtRIP]
    507 %else
    508         fld     qword [.s_r64QNan xWrtRIP]
    509 %endif
     478        ; Pops the two values off the FPU stack and returns +Inf.
     479        ;
     480.return_plus_inf:
     481        fld     qword [.s_r64PlusInf xWrtRIP]
    510482        jmp     .return_pop_pop_val
    511483
    512484        ;
    513         ; Pops the two values off the FPU stack and returns +Inf.
    514         ;
    515 .return_plus_inf:
    516 %ifdef RT_ARCH_AMD64
    517         movsd   xmm0, qword [.s_r64PlusInf xWrtRIP]
    518 %else
    519         fld     qword [.s_r64PlusInf xWrtRIP]
    520 %endif
     485        ; Pops the two values off the FPU stack and returns -Inf.
     486        ;
     487.return_minus_inf:
     488        fld     qword [.s_r64MinusInf xWrtRIP]
    521489        jmp     .return_pop_pop_val
    522490
    523491        ;
    524         ; Pops the two values off the FPU stack and returns -Inf.
    525         ;
    526 .return_minus_inf:
    527 %ifdef RT_ARCH_AMD64
    528         movsd   xmm0, qword [.s_r64MinusInf xWrtRIP]
    529 %else
    530         fld     qword [.s_r64MinusInf xWrtRIP]
    531 %endif
    532         jmp     .return_pop_pop_val
    533 
    534         ;
    535         ; AMD64: Return value in xmm0; Pop the two values on the FPU stack.
    536         ; X86:   Return st0, remove st1 and st2.
     492        ; Return st0, remove st1 and st2.
    537493        ;
    538494.return_pop_pop_val:
    539 %ifdef RT_ARCH_AMD64
    540         ffreep  st0
    541         ffreep  st0
    542 %else
     495        xor     eax, eax
     496.return_pop_pop_val_with_eax:
    543497        fstp    st2
    544498        ffreep  st0
    545 %endif
    546499        jmp     .return
    547500
     
    570523.s_r64MinusInf:
    571524        dq      RTFLOAT64U_INF_MINUS
    572 %ifdef RT_ARCH_AMD64
    573 .s_r64PlusOne:
    574         dq      +1.0
    575 .s_r64PlusZero:
    576         dq      +0.0
    577 .s_r64MinusZero:
    578         dq      -0.0
    579 %endif
    580525
    581526        ;;
     
    586531        ;
    587532.is_exp_odd_integer:
     533        ;
    588534        ; Save the FPU enviornment and mask all exceptions.
     535        ;
    589536        fnstenv [xBP - 30h]
    590537        mov     ax, [xBP - 30h + X86FSTENV32P.FCW]
     
    593540        mov     [xBP - 30h + X86FSTENV32P.FCW], ax
    594541
     542        ;
    595543        ; Convert to 64-bit integer (probably not 100% correct).
     544        ;
    596545        fld     st0                         ; -> st0=exponent st1=exponent; st2=base;
    597546        fistp   qword [xBP - 10h]
    598547        fild    qword [xBP - 10h]           ; -> st0=int(exponent) st1=exponent; st2=base;
    599548        fcomip  st0, st1                    ; -> st0=exponent; st1=base;
    600         jne     .is_exp_odd_integer_return_false ; jump if not integer.
     549        jne     .is_exp_odd_integer__return_false ; jump if not integer.
    601550        mov     xAX, [xBP - 10h]
    602551%ifdef
     
    604553%endif
    605554
     555        ;
    606556        ; Check the lowest bit if it might be odd.
     557        ; This works both for positive and negative numbers.
     558        ;
    607559        test    al, 1
    608         jz      .is_exp_odd_integer_return_false ; jump if even.
    609 
     560        jz      .is_exp_odd_integer__return_false ; jump if even.
     561
     562        ;
    610563        ; If the result is negative, convert to positive.
     564        ;
    611565%ifdef RT_ARCH_AMD64
    612566        bt      rax, 63
     
    614568        bt      edx, 31
    615569%endif
    616         jnc     .is_exp_odd_integer_positive
     570        jnc     .is_exp_odd_integer__positive
    617571%ifdef RT_ARCH_AMD64
    618572        neg     xAX
     
    622576        sbb     edx, 0
    623577%endif
    624 .is_exp_odd_integer_positive:
    625 
     578.is_exp_odd_integer__positive:
     579
     580        ;
    626581        ; Now find the most significant bit in the value so we can verify that
    627582        ; the odd bit was part of the mantissa/fraction of the input.
     583        ;
     584        cmp     bl, 3                            ; Skip if 80-bit input, as it has a 64-bit mantissa which
     585        je      .is_exp_odd_integer__return_true ; makes it a 1 bit more precision than out integer reg(s).
     586
    628587%ifdef RT_ARCH_AMD64
    629588        bsr     rax, rax
    630589%else
    631590        bsr     edx, edx
    632         jnz     .is_exp_odd_integer_high_dword_is_zero
     591        jnz     .is_exp_odd_integer__high_dword_is_zero
    633592        lea     eax, [edx + 20h]
    634         jmp     .is_exp_odd_integer_first_bit_in_eax
    635 .is_exp_odd_integer_high_dword_is_zero:
     593        jmp     .is_exp_odd_integer__first_bit_in_eax
     594.is_exp_odd_integer__high_dword_is_zero:
    636595        bsr     eax, eax
    637 .is_exp_odd_integer_first_bit_in_eax:
    638 %endif
    639         ; The limit is 53 for double precision (one implicit bit + 52 bits fraction).
    640         cmp     eax, 53
    641         jae     .is_exp_odd_integer_return_false
     596.is_exp_odd_integer__first_bit_in_eax:
     597%endif
     598        ;
     599        ; The limit is 53 for double precision (one implicit bit + 52 bits fraction),
     600        ; and 24 for single precision types.
     601        ;
     602        mov     ah, 53                      ; RTFLOAT64U_FRACTION_BITS + 1
     603        cmp     bl, 0
     604        jne     .is_exp_odd_integer__is_double_limit
     605        mov     ah, 24                      ; RTFLOAT32U_FRACTION_BITS + 1
     606.is_exp_odd_integer__is_double_limit:
     607
     608        cmp     al, ah
     609        jae     .is_exp_odd_integer__return_false
    642610        mov     eax, 1
    643         jmp     .is_exp_odd_integer_return
    644611
    645612        ; Return.
    646 .is_exp_odd_integer_return_false:
     613.is_exp_odd_integer__return_true:
     614        jmp     .is_exp_odd_integer__return
     615.is_exp_odd_integer__return_false:
    647616        xor     eax, eax
    648 .is_exp_odd_integer_return:
     617.is_exp_odd_integer__return:
    649618        ffreep  st0
    650619        fldenv  [xBP - 30h]
    651620        ret
    652621
    653 ENDPROC   RT_NOCRT(pow)
    654 
     622ENDPROC   rtNoCrtMathPowCore
     623
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette