Home | History | Annotate | Line # | Download | only in ia32
      1 /*	$NetBSD: math.c,v 1.1.1.2 2018/08/16 18:17:47 jmcneill Exp $	*/
      2 
      3 /*++
      4 
      5 Copyright (c) 1998  Intel Corporation
      6 
      7 Module Name:
      8 
      9     math.c
     10 
     11 Abstract:
     12 
     13 
     14 
     15 
     16 Revision History
     17 
     18 --*/
     19 
     20 #include "lib.h"
     21 
     22 
     23 //
     24 // Declare runtime functions
     25 //
     26 
     27 #ifdef RUNTIME_CODE
     28 #ifndef __GNUC__
     29 #pragma RUNTIME_CODE(LShiftU64)
     30 #pragma RUNTIME_CODE(RShiftU64)
     31 #pragma RUNTIME_CODE(MultU64x32)
     32 #pragma RUNTIME_CODE(DivU64x32)
     33 #endif
     34 #endif
     35 
     36 //
     37 //
     38 //
     39 
     40 UINT64
     41 LShiftU64 (
     42     IN UINT64   Operand,
     43     IN UINTN    Count
     44     )
     45 // Left shift 64bit by 32bit and get a 64bit result
     46 {
     47 #ifdef __GNUC__
     48     return Operand << Count;
     49 #else
     50     UINT64      Result;
     51     _asm {
     52         mov     eax, dword ptr Operand[0]
     53         mov     edx, dword ptr Operand[4]
     54         mov     ecx, Count
     55         and     ecx, 63
     56 
     57         shld    edx, eax, cl
     58         shl     eax, cl
     59 
     60         cmp     ecx, 32
     61         jc      short ls10
     62 
     63         mov     edx, eax
     64         xor     eax, eax
     65 
     66 ls10:
     67         mov     dword ptr Result[0], eax
     68         mov     dword ptr Result[4], edx
     69     }
     70 
     71     return Result;
     72 #endif
     73 }
     74 
     75 UINT64
     76 RShiftU64 (
     77     IN UINT64   Operand,
     78     IN UINTN    Count
     79     )
     80 // Right shift 64bit by 32bit and get a 64bit result
     81 {
     82 #ifdef __GNUC__
     83     return Operand >> Count;
     84 #else
     85     UINT64      Result;
     86     _asm {
     87         mov     eax, dword ptr Operand[0]
     88         mov     edx, dword ptr Operand[4]
     89         mov     ecx, Count
     90         and     ecx, 63
     91 
     92         shrd    eax, edx, cl
     93         shr     edx, cl
     94 
     95         cmp     ecx, 32
     96         jc      short rs10
     97 
     98         mov     eax, edx
     99         xor     edx, edx
    100 
    101 rs10:
    102         mov     dword ptr Result[0], eax
    103         mov     dword ptr Result[4], edx
    104     }
    105 
    106     return Result;
    107 #endif
    108 }
    109 
    110 
    111 UINT64
    112 MultU64x32 (
    113     IN UINT64   Multiplicand,
    114     IN UINTN    Multiplier
    115     )
    116 // Multiple 64bit by 32bit and get a 64bit result
    117 {
    118 #ifdef __GNUC__
    119     return Multiplicand * Multiplier;
    120 #else
    121     UINT64      Result;
    122     _asm {
    123         mov     eax, dword ptr Multiplicand[0]
    124         mul     Multiplier
    125         mov     dword ptr Result[0], eax
    126         mov     dword ptr Result[4], edx
    127         mov     eax, dword ptr Multiplicand[4]
    128         mul     Multiplier
    129         add     dword ptr Result[4], eax
    130     }
    131 
    132     return Result;
    133 #endif
    134 }
    135 
    136 UINT64
    137 DivU64x32 (
    138     IN UINT64   Dividend,
    139     IN UINTN    Divisor,
    140     OUT UINTN   *Remainder OPTIONAL
    141     )
    142 // divide 64bit by 32bit and get a 64bit result
    143 // N.B. only works for 31bit divisors!!
    144 {
    145 #if 0 && defined(__GNUC__) && !defined(__MINGW32__)
    146     if (Remainder)
    147         *Remainder = Dividend % Divisor;
    148     return Dividend / Divisor;
    149 #else
    150     UINT32      Rem;
    151     UINT32      bit;
    152 
    153     ASSERT (Divisor != 0);
    154     ASSERT ((Divisor >> 31) == 0);
    155 
    156     //
    157     // For each bit in the dividend
    158     //
    159 
    160     Rem = 0;
    161     for (bit=0; bit < 64; bit++) {
    162 #if defined(__GNUC__) || defined(__MINGW32__)
    163         asm (
    164             "shll	$1, %0\n\t"
    165             "rcll	$1, 4%0\n\t"
    166             "rcll	$1, %2\n\t"
    167             "mov	%2, %%eax\n\t"
    168             "cmp	%1, %%eax\n\t"
    169             "cmc\n\t"
    170             "sbb	%%eax, %%eax\n\t"
    171             "sub	%%eax, %0\n\t"
    172             "and	%1, %%eax\n\t"
    173             "sub	%%eax, %2"
    174             : /* no outputs */
    175             : "m"(Dividend), "m"(Divisor), "m"(Rem)
    176             : "cc","memory","%eax"
    177             );
    178 #else
    179         _asm {
    180             shl     dword ptr Dividend[0], 1    ; shift rem:dividend left one
    181             rcl     dword ptr Dividend[4], 1
    182             rcl     dword ptr Rem, 1
    183 
    184             mov     eax, Rem
    185             cmp     eax, Divisor                ; Is Rem >= Divisor?
    186             cmc                                 ; No - do nothing
    187             sbb     eax, eax                    ; Else,
    188             sub     dword ptr Dividend[0], eax  ;   set low bit in dividen
    189             and     eax, Divisor                ; and
    190             sub     Rem, eax                    ;   subtract divisor
    191         }
    192 #endif
    193     }
    194 
    195     if (Remainder) {
    196         *Remainder = Rem;
    197     }
    198 
    199     return Dividend;
    200 #endif
    201 }
    202