VirtualBox

Changeset 98508 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Feb 8, 2023 3:31:06 PM (2 years ago)
Author:
vboxsync
Message:

IPRT/vcc: Optimized unsigned 64-bit division implementation for the 32-bit Visual C++ compilers. bugref:10261

Location:
trunk/src/VBox/Runtime/common/compiler/vcc
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/compiler/vcc/RTVccUInt64Div.cpp

    r98493 r98508  
    4242
    4343
    44 DECLASM(void) RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientReminder)
     44DECLASM(void) RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientRemainder)
    4545{
    46     RTUInt64DivRem(&paQuotientReminder[0], &paQuotientReminder[1], &paDividendDivisor[0], &paDividendDivisor[1]);
     46    RTUInt64DivRem(&paQuotientRemainder[0], &paQuotientRemainder[1], &paDividendDivisor[0], &paDividendDivisor[1]);
    4747}
    4848
  • trunk/src/VBox/Runtime/common/compiler/vcc/x86-alldiv.asm

    r98495 r98508  
    4949
    5050;;
    51 ; Division of signed 64-bit values, returning both the quotient and reminder.
     51; Division of signed 64-bit values, returning both the quotient and remainder.
    5252;
    5353; @returns  EDX:EAX Quotient.
  • trunk/src/VBox/Runtime/common/compiler/vcc/x86-alldvrm.asm

    r98495 r98508  
    4949
    5050;;
    51 ; Division of signed 64-bit values, returning both the quotient and reminder.
     51; Division of signed 64-bit values, returning both the quotient and remainder.
    5252;
    5353; @returns  EDX:EAX Quotient, EBX:ECX Remainder.
  • trunk/src/VBox/Runtime/common/compiler/vcc/x86-allrem.asm

    r98495 r98508  
    4949
    5050;;
    51 ; Division of signed 64-bit values, returning the reminder.
     51; Division of signed 64-bit values, returning the remainder.
    5252;
    5353; @returns  EDX:EAX Remainder.
  • trunk/src/VBox/Runtime/common/compiler/vcc/x86-aulldiv.asm

    r98493 r98508  
    5858        push    ebp
    5959        mov     ebp, esp
    60         sub     esp, 10h                    ; space for quotient and reminder.
     60        sub     esp, 10h                    ; space for quotient and remainder.
    6161
    62         ; Call RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientReminder)
     62        ; Call RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientRemainder)
    6363        mov     edx, esp
    6464        push    edx
  • trunk/src/VBox/Runtime/common/compiler/vcc/x86-aulldvrm.asm

    r98493 r98508  
    4949
    5050;;
    51 ; Division of unsigned 64-bit values, returning both quotient and reminder.
     51; Division of unsigned 64-bit values, returning both quotient and remainder.
    5252;
    5353; @returns  Quotient in edx:eax, remainder in ebx:ecx.
     
    6060        push    ebp
    6161        mov     ebp, esp
    62         sub     esp, 10h                    ; space for quotient and reminder.
    6362
    64         ; Call RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientReminder)
     63%define DIVIDEND_LO ebp + 08h
     64%define DIVIDEND_HI ebp + 0ch
     65%define DIVISOR_LO  ebp + 10h
     66%define DIVISOR_HI  ebp + 14h
     67
     68        ;
     69        ; If the divisor is only 32-bit wide as we can do a two-step division on 32-bit units.
     70        ;
     71        mov     ebx, [DIVISOR_HI]
     72        or      ebx, ebx
     73        jnz     .full_64_bit_divisor
     74
     75        ; step 1: dividend_hi / divisor
     76        mov     ebx, [DIVISOR_LO]
     77        mov     eax, [DIVIDEND_HI]
     78        xor     edx, edx
     79        div     ebx
     80        mov     ecx, eax                    ; high quotient bits.
     81
     82        ; step 2: (dividend_lo + step_1_remainder) / divisor
     83        mov     eax, [DIVIDEND_LO]          ; edx contains the remainder from the first step.
     84        div     ebx                         ; -> eax = low quotient, edx = remainder.
     85
     86        xchg    edx, ecx                    ; ecx = (low) remainder, edx = saved high quotient from step 1
     87        xor     ebx, ebx                    ; ebx = high remainder is zero, since divisor is 32-bit.
     88
     89        leave
     90        ret     10h
     91
     92%if 1
     93        ;
     94        ; The divisor is larger than 32 bits.
     95        ;
     96        ; We can approximate the quotient by reducing the divisor to 32 bits
     97        ; (reducing the dividend accordingly) and perform a 32-bit division.
     98        ; The result will be at most one off.
     99        ;
     100        ; The remainder has to be calculated using multiplication and
     101        ; subtraction.
     102        ;
     103.full_64_bit_divisor:
     104        push    edi
     105
     106        ; Find the shift count needed to reduce the divisor to 32-bit.
     107        bsr     ecx, ebx
     108        inc     cl
     109        test    cl, ~31
     110        jnz     .shift_32
     111
     112        ; Shift the divisor into edi.
     113        mov     edi, [DIVISOR_LO]
     114        shrd    edi, ebx, cl                ; edi = reduced divisor
     115
     116        ; Shift the dividend into edx:eax.
     117        mov     eax, [DIVIDEND_LO]
     118        mov     edx, [DIVIDEND_HI]
     119        shrd    eax, edx, cl
     120        shr     edx, cl
     121        jmp     .shifted
     122
     123.shift_32:  ; simplified version.
     124        mov     edi, ebx
     125        mov     eax, [DIVIDEND_HI]
     126        xor     edx, edx
     127.shifted:
     128
     129        ; Divide and save the approximate quotient (Qapprox) in edi.
     130        div     edi
     131        mov     edi, eax                    ; edi = Qapprox
     132
     133        ; Now multiply Qapprox with the divisor.
     134        mul     dword [DIVISOR_HI]
     135        mov     ecx, eax                    ; temporary storage
     136        mov     eax, [DIVISOR_LO]
     137        mul     edi
     138        add     edx, ecx                    ; edx:eax = QapproxDividend = Qapprox * divisor
     139
     140        ; Preload the dividend into ebx:ecx for remainder calculation and for adjusting Qapprox.
     141        mov     ecx, [DIVIDEND_LO]
     142        mov     ebx, [DIVIDEND_HI]
     143
     144        ; If carry is set, the result overflowed 64 bits, so the quotient must be too large.
     145        jc      .quotient_is_one_above_and_calc_remainder
     146
     147        ; Calculate the remainder, if this overflows (CF) it means Qapprox is
     148        ; one above and we need to reduce it and the adjust the remainder.
     149        sub     ecx, eax
     150        sbb     ebx, edx
     151        jc      .quotient_is_one_above
     152.done:
     153        mov     eax, edi
     154        xor     edx, edx
     155
     156        pop     edi
     157        leave
     158        ret     10h
     159
     160.quotient_is_one_above_and_calc_remainder:
     161        sub     ecx, eax
     162        sbb     ebx, edx
     163.quotient_is_one_above:
     164        add     ecx, [DIVISOR_LO]
     165        adc     ebx, [DIVISOR_HI]
     166        dec     edi
     167        jmp     .done
     168
     169%else
     170        ;
     171        ; Fall back on a rather slow C implementation.
     172        ;
     173.full_64_bit_divisor:
     174        ; Call RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientRemainder)
     175        sub     esp, 10h                    ; space for quotient and remainder.
    65176        mov     edx, esp
    66177        push    edx
     
    75186        mov     ecx, [ebp - 08h]
    76187        mov     ebx, [ebp - 08h + 4]
    77 
    78188        leave
    79189        ret     10h
     190
     191%endif
    80192ENDPROC_RAW     __aulldvrm
    81193
  • trunk/src/VBox/Runtime/common/compiler/vcc/x86-aullrem.asm

    r98494 r98508  
    4949
    5050;;
    51 ; Division of unsigned 64-bit values, returning the reminder.
     51; Division of unsigned 64-bit values, returning the remainder.
    5252;
    5353; @returns  Remainder in edx:eax.
     
    5858        push    ebp
    5959        mov     ebp, esp
    60         sub     esp, 10h                    ; space for quotient and reminder.
     60        sub     esp, 10h                    ; space for quotient and remainder.
    6161
    62         ; Call RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientReminder)
     62        ; Call RTVccUInt64Div(RTUINT64U const *paDividendDivisor, RTUINT64U *paQuotientRemainder)
    6363        mov     edx, esp
    6464        push    edx
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