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