Mercurial > projects > ldc
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 |