comparison druntime/src/compiler/dmd/llmath.d @ 1458:e0b2d67cfe7c

Added druntime (this should be removed once it works).
author Robert Clipsham <robert@octarineparrot.com>
date Tue, 02 Jun 2009 17:43:06 +0100
parents
children
comparison
equal deleted inserted replaced
1456:7b218ec1044f 1458:e0b2d67cfe7c
1 /**
2 * Support for 64-bit longs.
3 *
4 * Copyright: Copyright Digital Mars 1993 - 2009.
5 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
6 * Authors: Walter Bright, Sean Kelly
7 *
8 * Copyright Digital Mars 1993 - 2009.
9 * Distributed under the Boost Software License, Version 1.0.
10 * (See accompanying file LICENSE_1_0.txt or copy at
11 * http://www.boost.org/LICENSE_1_0.txt)
12 */
13 module rt.llmath;
14
15 extern (C):
16
17
18 /***************************************
19 * Unsigned long divide.
20 * Input:
21 * [EDX,EAX],[ECX,EBX]
22 * Output:
23 * [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
24 * [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
25 */
26
27 void __ULDIV__()
28 {
29 asm
30 {
31 naked ;
32 test ECX,ECX ;
33 jz uldiv ;
34
35 // if ECX > EDX, then quotient is 0 and remainder is [EDX,EAX]
36 cmp ECX,EDX ;
37 ja quo0 ;
38
39 test ECX,ECX ;
40 js Lleft ;
41
42 /* We have n>d, and know that n/d will fit in 32 bits.
43 * d will be left justified if we shift it left s bits.
44 * [d1,d0] <<= s
45 * [n2,n1,n0] = [n1,n0] << s
46 *
47 * Use one divide, by this reasoning:
48 * ([n2,n1]<<32 + n0)/(d1<<32 + d0)
49 * becomes:
50 * ([n2,n1]<<32)/(d1<<32 + d0) + n0/(d1<<32 + d0)
51 * The second divide is always 0.
52 * Ignore the d0 in the first divide, which will yield a quotient
53 * that might be too high by 1 (because d1 is left justified).
54 * We can tell if it's too big if:
55 * q*[d1,d0] > [n2,n1,n0]
56 * which is:
57 * q*[d1,d0] > [[q*[d1,0]+q%[d1,0],n1,n0]
58 * If we subtract q*[d1,0] from both sides, we get:
59 * q*d0 > [[n2,n1]%d1,n0]
60 * So if it is too big by one, reduce q by one to q'=q-one.
61 * Compute remainder as:
62 * r = ([n1,n0] - q'*[d1,d0]) >> s
63 * Again, we can subtract q*[d1,0]:
64 * r = ([n1,n0] - q*[d1,0] - (q'*[d1,d0] - q*[d1,0])) >> s
65 * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - (q - one)*[d1,d0])) >> s
66 * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - [d1 *(q-one),d0*(1-q)])) >> s
67 * r = ([[n2,n1]%d1,n0] + [d1 *one,d0*(one-q)])) >> s
68 */
69
70 push EBP ;
71 push ESI ;
72 push EDI ;
73
74 mov ESI,EDX ;
75 mov EDI,EAX ;
76 mov EBP,ECX ;
77
78 bsr EAX,ECX ; // EAX is now 30..0
79 xor EAX,0x1F ; // EAX is now 1..31
80 mov CH,AL ;
81 neg EAX ;
82 add EAX,32 ;
83 mov CL,AL ;
84
85 mov EAX,EBX ;
86 shr EAX,CL ;
87 xchg CH,CL ;
88 shl EBP,CL ;
89 or EBP,EAX ;
90 shl EBX,CL ;
91
92 mov EDX,ESI ;
93 xchg CH,CL ;
94 shr EDX,CL ;
95
96 mov EAX,EDI ;
97 shr EAX,CL ;
98 xchg CH,CL ;
99 shl EDI,CL ;
100 shl ESI,CL ;
101 or EAX,ESI ;
102
103 div EBP ;
104 push EBP ;
105 mov EBP,EAX ;
106 mov ESI,EDX ;
107
108 mul EBX ;
109 cmp EDX,ESI ;
110 ja L1 ;
111 jb L2 ;
112 cmp EAX,EDI ;
113 jbe L2 ;
114 L1: dec EBP ;
115 sub EAX,EBX ;
116 sbb EDX,0[ESP] ;
117 L2:
118 add ESP,4 ;
119 sub EDI,EAX ;
120 sbb ESI,EDX ;
121 mov EAX,ESI ;
122 xchg CH,CL ;
123 shl EAX,CL ;
124 xchg CH,CL ;
125 shr EDI,CL ;
126 or EDI,EAX ;
127 shr ESI,CL ;
128 mov EBX,EDI ;
129 mov ECX,ESI ;
130 mov EAX,EBP ;
131 xor EDX,EDX ;
132
133 pop EDI ;
134 pop ESI ;
135 pop EBP ;
136 ret ;
137
138 uldiv: test EDX,EDX ;
139 jnz D3 ;
140 // Both high words are 0, we can use the DIV instruction
141 div EBX ;
142 mov EBX,EDX ;
143 mov EDX,ECX ; // EDX = ECX = 0
144 ret ;
145
146 even ;
147 D3: // Divide [EDX,EAX] by EBX
148 mov ECX,EAX ;
149 mov EAX,EDX ;
150 xor EDX,EDX ;
151 div EBX ;
152 xchg ECX,EAX ;
153 div EBX ;
154 // ECX,EAX = result
155 // EDX = remainder
156 mov EBX,EDX ;
157 mov EDX,ECX ;
158 xor ECX,ECX ;
159 ret ;
160
161 quo0: // Quotient is 0
162 // Remainder is [EDX,EAX]
163 mov EBX,EAX ;
164 mov ECX,EDX ;
165 xor EAX,EAX ;
166 xor EDX,EDX ;
167 ret ;
168
169 Lleft: // The quotient is 0 or 1 and EDX >= ECX
170 cmp EDX,ECX ;
171 ja quo1 ; // [EDX,EAX] > [ECX,EBX]
172 // EDX == ECX
173 cmp EAX,EBX ;
174 jb quo0 ;
175
176 quo1: // Quotient is 1
177 // Remainder is [EDX,EAX] - [ECX,EBX]
178 sub EAX,EBX ;
179 sbb EDX,ECX ;
180 mov EBX,EAX ;
181 mov ECX,EDX ;
182 mov EAX,1 ;
183 xor EDX,EDX ;
184 ret ;
185 }
186 }
187
188
189 /***************************************
190 * Signed long divide.
191 * Input:
192 * [EDX,EAX],[ECX,EBX]
193 * Output:
194 * [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
195 * [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
196 * ESI,EDI destroyed
197 */
198
199 void __LDIV__()
200 {
201 asm
202 {
203 naked ;
204 test EDX,EDX ; // [EDX,EAX] negative?
205 jns L10 ; // no
206 //neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX]
207 neg EDX ;
208 neg EAX ;
209 sbb EDX,0 ;
210 test ECX,ECX ; // [ECX,EBX] negative?
211 jns L11 ; // no
212 //neg64 ECX,EBX ;
213 neg ECX ;
214 neg EBX ;
215 sbb ECX,0 ;
216 call __ULDIV__ ;
217 //neg64 ECX,EBX ; // remainder same sign as dividend
218 neg ECX ;
219 neg EBX ;
220 sbb ECX,0 ;
221 ret ;
222
223 L11: call __ULDIV__ ;
224 //neg64 ECX,EBX ; // remainder same sign as dividend
225 neg ECX ;
226 neg EBX ;
227 sbb ECX,0 ;
228 //neg64 EDX,EAX ; // quotient is negative
229 neg EDX ;
230 neg EAX ;
231 sbb EDX,0 ;
232 ret ;
233
234 L10: test ECX,ECX ; // [ECX,EBX] negative?
235 jns L12 ; // no (all is positive)
236 //neg64 ECX,EBX ;
237 neg ECX ;
238 neg EBX ;
239 sbb ECX,0 ;
240 call __ULDIV__ ;
241 //neg64 EDX,EAX ; // quotient is negative
242 neg EDX ;
243 neg EAX ;
244 sbb EDX,0 ;
245 ret ;
246
247 L12: jmp __ULDIV__ ;
248 }
249 }
250
251
252 /***************************************
253 * Compare [EDX,EAX] with [ECX,EBX]
254 * Signed
255 * Returns result in flags
256 */
257
258 void __LCMP__()
259 {
260 asm
261 {
262 naked ;
263 cmp EDX,ECX ;
264 jne C1 ;
265 push EDX ;
266 xor EDX,EDX ;
267 cmp EAX,EBX ;
268 jz C2 ;
269 ja C3 ;
270 dec EDX ;
271 pop EDX ;
272 ret ;
273
274 C3: inc EDX ;
275 C2: pop EDX ;
276 C1: ret ;
277 }
278 }
279
280
281
282
283 // Convert ulong to real
284
285 private __gshared real adjust = cast(real)0x800_0000_0000_0000 * 0x10;
286
287 real __U64_LDBL()
288 {
289 version (OSX)
290 { /* OSX version has to be concerned about 16 byte stack
291 * alignment and the inability to reference the data segment
292 * because of PIC.
293 */
294 asm
295 { naked ;
296 push EDX ;
297 push EAX ;
298 and dword ptr 4[ESP], 0x7FFFFFFF ;
299 fild qword ptr [ESP] ;
300 test EDX,EDX ;
301 jns L1 ;
302 push 0x0000403e ;
303 push 0x80000000 ;
304 push 0 ;
305 fld real ptr [ESP] ; // adjust
306 add ESP,12 ;
307 faddp ST(1), ST ;
308 L1: ;
309 add ESP, 8 ;
310 ret ;
311 }
312 }
313 else
314 {
315 asm
316 { naked ;
317 push EDX ;
318 push EAX ;
319 and dword ptr 4[ESP], 0x7FFFFFFF ;
320 fild qword ptr [ESP] ;
321 test EDX,EDX ;
322 jns L1 ;
323 fld real ptr adjust ;
324 faddp ST(1), ST ;
325 L1: ;
326 add ESP, 8 ;
327 ret ;
328 }
329 }
330 }
331
332 // Same as __U64_LDBL, but return result as double in [EDX,EAX]
333 ulong __ULLNGDBL()
334 {
335 asm
336 { naked ;
337 call __U64_LDBL ;
338 sub ESP,8 ;
339 fstp double ptr [ESP] ;
340 pop EAX ;
341 pop EDX ;
342 ret ;
343 }
344 }
345
346 // Convert double to ulong
347
348 private __gshared short roundTo0 = 0xFBF;
349
350 ulong __DBLULLNG()
351 {
352 // BUG: should handle NAN's and overflows
353 version (OSX)
354 {
355 asm
356 { naked ;
357 push 0xFBF ; // roundTo0
358 push 0x0000403e ;
359 push 0x80000000 ;
360 push 0 ; // adjust
361 push EDX ;
362 push EAX ;
363 fld double ptr [ESP] ;
364 sub ESP,8 ;
365 fld real ptr 16[ESP] ; // adjust
366 fcomp ;
367 fstsw AX ;
368 fstcw 8[ESP] ;
369 fldcw 28[ESP] ; // roundTo0
370 sahf ;
371 jae L1 ;
372 fld real ptr 16[ESP] ; // adjust
373 fsubp ST(1), ST ;
374 fistp qword ptr [ESP] ;
375 pop EAX ;
376 pop EDX ;
377 fldcw [ESP] ;
378 add ESP,24 ;
379 add EDX,0x8000_0000 ;
380 ret ;
381 L1: ;
382 fistp qword ptr [ESP] ;
383 pop EAX ;
384 pop EDX ;
385 fldcw [ESP] ;
386 add ESP,24 ;
387 ret ;
388 }
389 }
390 else
391 {
392 asm
393 { naked ;
394 push EDX ;
395 push EAX ;
396 fld double ptr [ESP] ;
397 sub ESP,8 ;
398 fld real ptr adjust ;
399 fcomp ;
400 fstsw AX ;
401 fstcw 8[ESP] ;
402 fldcw roundTo0 ;
403 sahf ;
404 jae L1 ;
405 fld real ptr adjust ;
406 fsubp ST(1), ST ;
407 fistp qword ptr [ESP] ;
408 pop EAX ;
409 pop EDX ;
410 fldcw [ESP] ;
411 add ESP,8 ;
412 add EDX,0x8000_0000 ;
413 ret ;
414 L1: ;
415 fistp qword ptr [ESP] ;
416 pop EAX ;
417 pop EDX ;
418 fldcw [ESP] ;
419 add ESP,8 ;
420 ret ;
421 }
422 }
423 }
424
425 // Convert double in ST0 to uint
426
427 uint __DBLULNG()
428 {
429 // BUG: should handle NAN's and overflows
430 version (OSX)
431 {
432 asm
433 { naked ;
434 push 0xFBF ; // roundTo0
435 sub ESP,12 ;
436 fstcw 8[ESP] ;
437 fldcw 12[ESP] ; // roundTo0
438 fistp qword ptr [ESP] ;
439 fldcw 8[ESP] ;
440 pop EAX ;
441 add ESP,12 ;
442 ret ;
443 }
444 }
445 else
446 {
447 asm
448 { naked ;
449 sub ESP,16 ;
450 fstcw 8[ESP] ;
451 fldcw roundTo0 ;
452 fistp qword ptr [ESP] ;
453 fldcw 8[ESP] ;
454 pop EAX ;
455 add ESP,12 ;
456 ret ;
457 }
458 }
459 }
460
461 // Convert real in ST0 to ulong
462
463 ulong __LDBLULLNG()
464 {
465 version (OSX)
466 {
467 asm
468 { naked ;
469 push 0xFBF ; // roundTo0
470 push 0x0000403e ;
471 push 0x80000000 ;
472 push 0 ; // adjust
473 sub ESP,16 ;
474 fld real ptr 16[ESP] ; // adjust
475 fcomp ;
476 fstsw AX ;
477 fstcw 8[ESP] ;
478 fldcw 28[ESP] ; // roundTo0
479 sahf ;
480 jae L1 ;
481 fld real ptr 16[ESP] ; // adjust
482 fsubp ST(1), ST ;
483 fistp qword ptr [ESP] ;
484 pop EAX ;
485 pop EDX ;
486 fldcw [ESP] ;
487 add ESP,24 ;
488 add EDX,0x8000_0000 ;
489 ret ;
490 L1: ;
491 fistp qword ptr [ESP] ;
492 pop EAX ;
493 pop EDX ;
494 fldcw [ESP] ;
495 add ESP,24 ;
496 ret ;
497 }
498 }
499 else
500 {
501 asm
502 { naked ;
503 sub ESP,16 ;
504 fld real ptr adjust ;
505 fcomp ;
506 fstsw AX ;
507 fstcw 8[ESP] ;
508 fldcw roundTo0 ;
509 sahf ;
510 jae L1 ;
511 fld real ptr adjust ;
512 fsubp ST(1), ST ;
513 fistp qword ptr [ESP] ;
514 pop EAX ;
515 pop EDX ;
516 fldcw [ESP] ;
517 add ESP,8 ;
518 add EDX,0x8000_0000 ;
519 ret ;
520 L1: ;
521 fistp qword ptr [ESP] ;
522 pop EAX ;
523 pop EDX ;
524 fldcw [ESP] ;
525 add ESP,8 ;
526 ret ;
527 }
528 }
529 }
530
531