Imported Upstream version 3.0
[platform/upstream/gnu-efi.git] / lib / ia32 / math.c
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 #ifdef __GNUC__
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         _asm {
161             shl     dword ptr Dividend[0], 1    ; shift rem:dividend left one
162             rcl     dword ptr Dividend[4], 1    
163             rcl     dword ptr Rem, 1            
164
165             mov     eax, Rem
166             cmp     eax, Divisor                ; Is Rem >= Divisor?
167             cmc                                 ; No - do nothing
168             sbb     eax, eax                    ; Else, 
169             sub     dword ptr Dividend[0], eax  ;   set low bit in dividen
170             and     eax, Divisor                ; and
171             sub     Rem, eax                    ;   subtract divisor 
172         }
173     }
174
175     if (Remainder) {
176         *Remainder = Rem;
177     }
178
179     return Dividend;
180 #endif
181 }