]> git.llucax.com Git - software/druntime.git/blob - src/compiler/dmd/llmath.d
Fixed a few mistakes regarding invariance, etc, between D1 and D2.
[software/druntime.git] / src / compiler / dmd / llmath.d
1 // llmath.d
2 // Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com
3 // All Rights Reserved
4 // Written by Walter Bright
5
6 module rt.llmath;
7
8 // Compiler runtime support for 64 bit longs
9
10 extern (C):
11
12
13 /***************************************
14  * Unsigned long divide.
15  * Input:
16  *      [EDX,EAX],[ECX,EBX]
17  * Output:
18  *      [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
19  *      [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
20  *      ESI,EDI destroyed
21  */
22
23 void __ULDIV__()
24 {
25     asm
26     {
27         naked                   ;
28         test    ECX,ECX         ;
29         jz      uldiv           ;
30
31         push    EBP             ;
32
33         // left justify [ECX,EBX] and leave count of shifts + 1 in EBP
34
35         mov     EBP,1           ;       // at least 1 shift
36         test    ECX,ECX         ;       // left justified?
37         js      L1              ;       // yes
38         jnz     L2              ;
39         add     EBP,8           ;
40         mov     CH,CL           ;
41         mov     CL,BH           ;
42         mov     BH,BL           ;
43         xor     BL,BL           ;       // [ECX,EBX] <<= 8
44         test    ECX,ECX         ;
45         js      L1              ;
46         even                    ;
47 L2:     inc     EBP             ;       // another shift
48         shl     EBX,1           ;
49         rcl     ECX,1           ;       // [ECX,EBX] <<= 1
50         jno     L2              ;       // not left justified yet
51
52 L1:     mov     ESI,ECX         ;
53         mov     EDI,EBX         ;       // [ESI,EDI] = divisor
54
55         mov     ECX,EDX         ;
56         mov     EBX,EAX         ;       // [ECX,EBX] = [EDX,EAX]
57         xor     EAX,EAX         ;
58         cdq                     ;       // [EDX,EAX] = 0
59         even                    ;
60 L4:     cmp     ESI,ECX         ;       // is [ECX,EBX] > [ESI,EDI]?
61         ja      L3              ;       // yes
62         jb      L5              ;       // definitely less than
63         cmp     EDI,EBX         ;       // check low order word
64         ja      L3              ;
65 L5:     sub     EBX,EDI         ;
66         sbb     ECX,ESI         ;       // [ECX,EBX] -= [ESI,EDI]
67         stc                     ;       // rotate in a 1
68 L3:     rcl     EAX,1           ;
69         rcl     EDX,1           ;       // [EDX,EAX] = ([EDX,EAX] << 1) + C
70         shr     ESI,1           ;
71         rcr     EDI,1           ;       // [ESI,EDI] >>= 1
72         dec     EBP             ;       // control count
73         jne     L4              ;
74         pop     EBP             ;
75         ret                     ;
76
77 div0:   mov     EAX,-1          ;
78         cwd                     ;       // quotient is -1
79 //      xor     ECX,ECX         ;
80 //      mov     EBX,ECX         ;       // remainder is 0 (ECX and EBX already 0)
81         pop     EBP             ;
82         ret                     ;
83
84 uldiv:  test    EDX,EDX         ;
85         jnz     D3              ;
86         // Both high words are 0, we can use the DIV instruction
87         div     EBX             ;
88         mov     EBX,EDX         ;
89         mov     EDX,ECX         ;       // EDX = ECX = 0
90         ret                     ;
91
92         even                    ;
93 D3:     // Divide [EDX,EAX] by EBX
94         mov     ECX,EAX         ;
95         mov     EAX,EDX         ;
96         xor     EDX,EDX         ;
97         div     EBX             ;
98         xchg    ECX,EAX         ;
99         div     EBX             ;
100         // ECX,EAX = result
101         // EDX = remainder
102         mov     EBX,EDX         ;
103         mov     EDX,ECX         ;
104         xor     ECX,ECX         ;
105         ret                     ;
106     }
107 }
108
109
110 /***************************************
111  * Signed long divide.
112  * Input:
113  *      [EDX,EAX],[ECX,EBX]
114  * Output:
115  *      [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
116  *      [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
117  *      ESI,EDI destroyed
118  */
119
120 void __LDIV__()
121 {
122     asm
123     {
124         naked                   ;
125         test    EDX,EDX         ;       // [EDX,EAX] negative?
126         jns     L10             ;       // no
127         //neg64 EDX,EAX         ;       // [EDX,EAX] = -[EDX,EAX]
128           neg   EDX             ;
129           neg   EAX             ;
130           sbb   EDX,0           ;
131         test    ECX,ECX         ;       // [ECX,EBX] negative?
132         jns     L11             ;       // no
133         //neg64 ECX,EBX         ;
134           neg   ECX             ;
135           neg   EBX             ;
136           sbb   ECX,0           ;
137         call    __ULDIV__       ;
138         //neg64 ECX,EBX         ;       // remainder same sign as dividend
139           neg   ECX             ;
140           neg   EBX             ;
141           sbb   ECX,0           ;
142         ret                     ;
143
144 L11:    call    __ULDIV__       ;
145         //neg64 ECX,EBX         ;       // remainder same sign as dividend
146           neg   ECX             ;
147           neg   EBX             ;
148           sbb   ECX,0           ;
149         //neg64 EDX,EAX         ;       // quotient is negative
150           neg   EDX             ;
151           neg   EAX             ;
152           sbb   EDX,0           ;
153         ret                     ;
154
155 L10:    test    ECX,ECX         ;       // [ECX,EBX] negative?
156         jns     L12             ;       // no (all is positive)
157         //neg64 ECX,EBX         ;
158           neg   ECX             ;
159           neg   EBX             ;
160           sbb   ECX,0           ;
161         call    __ULDIV__       ;
162         //neg64 EDX,EAX         ;       // quotient is negative
163           neg   EDX             ;
164           neg   EAX             ;
165           sbb   EDX,0           ;
166         ret                     ;
167
168 L12:    jmp     __ULDIV__       ;
169     }
170 }
171
172
173 /***************************************
174  * Compare [EDX,EAX] with [ECX,EBX]
175  * Signed
176  * Returns result in flags
177  */
178
179 void __LCMP__()
180 {
181     asm
182     {
183         naked                   ;
184         cmp     EDX,ECX         ;
185         jne     C1              ;
186         push    EDX             ;
187         xor     EDX,EDX         ;
188         cmp     EAX,EBX         ;
189         jz      C2              ;
190         ja      C3              ;
191         dec     EDX             ;
192         pop     EDX             ;
193         ret                     ;
194
195 C3:     inc     EDX             ;
196 C2:     pop     EDX             ;
197 C1:     ret                     ;
198     }
199 }
200
201
202
203
204 // Convert ulong to real
205
206 private real adjust = cast(real)0x800_0000_0000_0000 * 0x10;
207
208 real __U64_LDBL()
209 {
210     asm
211     {   naked                                   ;
212         push    EDX                             ;
213         push    EAX                             ;
214         and     dword ptr 4[ESP], 0x7FFFFFFF    ;
215         fild    qword ptr [ESP]                 ;
216         test    EDX,EDX                         ;
217         jns     L1                              ;
218         fld     real ptr adjust                 ;
219         faddp   ST(1), ST                       ;
220     L1:                                         ;
221         add     ESP, 8                          ;
222         ret                                     ;
223     }
224 }
225
226 // Same as __U64_LDBL, but return result as double in [EDX,EAX]
227 ulong __ULLNGDBL()
228 {
229     asm
230     {   naked                                   ;
231         call __U64_LDBL                         ;
232         sub  ESP,8                              ;
233         fstp double ptr [ESP]                   ;
234         pop  EAX                                ;
235         pop  EDX                                ;
236         ret                                     ;
237     }
238 }
239
240 // Convert double to ulong
241
242 private short roundTo0 = 0xFBF;
243
244 ulong __DBLULLNG()
245 {
246     // BUG: should handle NAN's and overflows
247     asm
248     {   naked                                   ;
249         push    EDX                             ;
250         push    EAX                             ;
251         fld     double ptr [ESP]                ;
252         sub     ESP,8                           ;
253         fld     real ptr adjust                 ;
254         fcomp                                   ;
255         fstsw   AX                              ;
256         fstcw   8[ESP]                          ;
257         fldcw   roundTo0                        ;
258         sahf                                    ;
259         jae     L1                              ;
260         fld     real ptr adjust                 ;
261         fsubp   ST(1), ST                       ;
262         fistp   qword ptr [ESP]                 ;
263         pop     EAX                             ;
264         pop     EDX                             ;
265         fldcw   [ESP]                           ;
266         add     ESP,8                           ;
267         add     EDX,0x8000_0000                 ;
268         ret                                     ;
269     L1:                                         ;
270         fistp   qword ptr [ESP]                 ;
271         pop     EAX                             ;
272         pop     EDX                             ;
273         fldcw   [ESP]                           ;
274         add     ESP,8                           ;
275         ret                                     ;
276     }
277 }
278
279 // Convert double in ST0 to uint
280
281 uint __DBLULNG()
282 {
283     // BUG: should handle NAN's and overflows
284     asm
285     {   naked                                   ;
286         sub     ESP,16                          ;
287         fstcw   8[ESP]                          ;
288         fldcw   roundTo0                        ;
289         fistp   qword ptr [ESP]                 ;
290         fldcw   8[ESP]                          ;
291         pop     EAX                             ;
292         add     ESP,12                          ;
293         ret                                     ;
294     }
295 }