[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / eng / i386 / floatobj.S
1 /*
2 * COPYRIGHT: LGPL, see LGPL.txt in the top level directory
3 * PROJECT: ReactOS Win32 subsystem
4 * PURPOSE: FLOATOBJ floating point emulation functions for x86
5 * FILE: subsystems/win32/win32k/objects/i386/floatobj.S
6 * PROGRAMMER: Timo Kreuzer
7 */
8
9 #include <asm.inc>
10
11 .code
12
13 /*******************************************************************************
14 * IEEE 754-1985 single precision floating point
15 *
16 * | 31 | 30...23 | 22...0 |
17 * |sign| exponent | fraction |
18 *
19 * mantissa = 1 + (fraction / 2^23)
20 * f = (-1)^sign * mantissa * 2 ^ (exponent - bias)
21 * bias = 127
22 *
23 *******************************************************************************
24 * win32k x86 floating point emulation
25 *
26 * struct _EFLOAT
27 = {
28 * LONG lMant;
29 * LONG lExp;
30 * };
31 *
32 * f = (lMant / 0x40000000) * 2 ^ (lExp - 2)
33 * = lMant * 2 ^ (lExp - 32)
34 *
35 *******************************************************************************
36 * Optimization notes:
37 *
38 * - shld is slow (4 cycles) and not pairable, mov + shl is faster
39 * - esp is used, because it's available earlier
40 * - bsr is very slow on old cpus (up to 72 cycles on a p1) while being much
41 * faster on modern cpus (2-11 cycles). Workarounds using branch trees or
42 * table lookups are of no use nowadays.
43 *******************************************************************************
44 * Compatibility notes:
45 * - There are issues with very large size values near integer overflow.
46 * Floating point values are behaving different there. This behavior isn't
47 * simulated yet. Difference is < 10^-5 %
48 * - The result of a multiplication can differ from Windows result in the
49 * least significant bit, that is a difference of 1 / 2^30 or ~10^-9
50 *******************************************************************************
51 * Implementation status:
52 *
53 * FLOATOBJ_SetFloat - implemented, tested
54 * FLOATOBJ_SetLong - implemented, tested
55 * FLOATOBJ_GetFloat - implemented, tested
56 * FLOATOBJ_GetLong - implemented, tested
57 * FLOATOBJ_Equal - implemented, tested
58 * FLOATOBJ_EqualLong - implemented
59 * FLOATOBJ_GreaterThan - implemented
60 * FLOATOBJ_GreaterThanLong - wrapper
61 * FLOATOBJ_LessThan - implemented
62 * FLOATOBJ_LessThanLong - wrapper
63 * FLOATOBJ_Neg - implemented
64 * FLOATOBJ_Mul - implemented, tested, optimized
65 * FLOATOBJ_MulFloat - wrapper
66 * FLOATOBJ_MulLong - wrapper, could really need optimization
67 * FLOATOBJ_Div - implemented
68 * FLOATOBJ_DivFloat - wrapper
69 * FLOATOBJ_DivLong - wrapper
70 * FLOATOBJ_Add - implemented, tested
71 * FLOATOBJ_AddFloat - wrapper
72 * FLOATOBJ_AddLong - wrapper
73 * FLOATOBJ_Sub - implemented, tested
74 * FLOATOBJ_SubFloat - wrapper
75 * FLOATOBJ_SubLong - wrapper
76 */
77
78 #define lMant 0
79 #define lExp 4
80
81 #define PARAM1 8
82 #define PARAM2 12
83
84 /******************************************************************************
85 * VOID
86 * APIENTRY
87 * FLOATOBJ_SetFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
88 */
89 _FLOATOBJ_SetFloat@8:
90 PUBLIC _FLOATOBJ_SetFloat@8
91 push ebp
92 mov ebp, esp
93
94 mov ecx, [esp + PARAM2] /* Load the float into ecx */
95 mov eax, ecx /* Copy float to eax for later */
96
97 test ecx, HEX(7f800000) /* Check for zero exponent - 0 or denormal */
98 jz SetFloat0 /* If it's all zero, ... */
99
100 shl ecx, 7 /* Put the bits for the mantissa in place */
101
102 cdq /* Fill edx with the sign from the FLOATL in eax */
103 and ecx, HEX(7fffffff) /* Mask out invalid field in the mantissa */
104
105 shr eax, 23 /* Shift the exponent in eax in place */
106 or ecx, HEX(40000000) /* Set bit for 1 in the mantissa */
107 and eax, HEX(0ff) /* Mask out invalid fields in the exponent in eax */
108
109 xor ecx, edx /* Make use of the sign bit expanded to full edx */
110
111 sub eax, 125 /* Adjust exonent bias */
112
113 sub ecx, edx /* Substract -1 or add 1 if sign was set */
114
115 mov edx, [esp + PARAM1] /* Load pf into edx */
116 mov [edx + lMant], ecx /* Save back mantissa */
117 mov [edx + lExp], eax /* Save back exponent */
118
119 pop ebp /* Return */
120 ret 8
121
122 SetFloat0:
123 mov edx, [esp + PARAM1] /* Load pf into edx */
124
125 mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */
126 mov dword ptr [edx + lExp], 0
127
128 pop ebp /* Return */
129 ret 8
130
131
132 /*******************************************************************************
133 * LONG
134 * APIENTRY
135 * FLOATOBJ_GetFloat(IN PFLOATOBJ pf);
136 *
137 */
138 _FLOATOBJ_GetFloat@4:
139 PUBLIC _FLOATOBJ_GetFloat@4
140 push ebp
141 mov ebp, esp
142
143 mov edx, [esp + PARAM1] /* Load pf into edx */
144 mov eax, [edx + lMant] /* Load mantissa into eax */
145 mov ecx, [edx + lExp] /* Load exponent into ecx */
146
147 cdq /* Calculate abs(mantissa) */
148 xor eax, edx
149
150 add ecx, 125
151
152 sub eax, edx
153 jz GetFloatRet
154
155 and ecx, HEX(0ff) /* Mask out invalid fields in the exponent */
156 and eax, HEX(3fffffff) /* Mask out invalid fields in mantissa */
157
158 shl ecx, 23 /* Shift exponent in place */
159 shr eax, 7 /* Shift mantissa in place */
160
161 and edx, HEX(80000000) /* Reduce edx to sign bit only */
162
163 or eax, ecx /* Set exponent in result */
164 or eax, edx /* Set sign bit in result */
165
166 GetFloatRet:
167 /* Return */
168 pop ebp
169 ret 4
170
171
172
173 /******************************************************************************
174 * VOID
175 * APIENTRY
176 * FLOATOBJ_SetLong(OUT PFLOATOBJ pf, IN LONG l);
177 *
178 * Instead of using abs(l), which is 3 + 2 instructions, use a branch.
179 */
180 _FLOATOBJ_SetLong@8:
181 PUBLIC _FLOATOBJ_SetLong@8
182 push ebp
183 mov ebp, esp
184
185 mov eax, [esp + PARAM2] /* Load l into eax */
186 mov edx, [esp + PARAM1] /* Load pf into edx */
187
188 test eax, eax /* different handling for <0, =0 and >0 */
189 js SetLongNeg
190 jz SetLong0
191
192 bsr ecx, eax /* Get number of most significant bit aka log2(l) */
193 mov [edx + lExp], ecx /* Safe log2(l) into exponent */
194
195 neg ecx /* Calculate necessary shift */
196 add ecx, 30
197
198 add dword ptr [edx + lExp], 2 /* Adjust exponent */
199
200 shl eax, cl /* Shift mantissa in place */
201 mov [edx + lMant], eax /* Save mantissa */
202
203 pop ebp /* Return */
204 ret 8
205
206 SetLongNeg:
207 neg eax /* Get absolute value of l */
208 bsr ecx, eax /* Get number of most significant bit aka log2(l) */
209 neg eax /* Back to negative */
210
211 mov [edx + lExp], ecx /* Safe log2(-l) into exponent */
212
213 neg ecx /* Calculate necessary shift */
214 add ecx, 30
215
216 add dword ptr [edx + lExp], 2 /* Adjust exponent */
217
218 shl eax, cl /* Shift mantissa in place */
219 mov [edx + lMant], eax /* Save mantissa */
220
221 pop ebp /* Return */
222 ret 8
223
224 SetLong0:
225 mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */
226 mov dword ptr [edx + lExp], 0
227
228 pop ebp /* Return */
229 ret 8
230
231
232 /*******************************************************************************
233 * LONG
234 * APIENTRY
235 * FLOATOBJ_GetLong(IN PFLOATOBJ pf);
236 *
237 */
238 _FLOATOBJ_GetLong@4:
239 PUBLIC _FLOATOBJ_GetLong@4
240 push ebp
241 mov ebp, esp
242
243 mov edx, [ebp + PARAM1] /* Load pf into edx */
244 mov ecx, 32 /* Load (32 - lExp) into ecx */
245 sub ecx, [edx + lExp]
246 jle short GetLong2 /* Check for Overflow */
247
248 mov eax, [edx + lMant] /* Load mantissa into eax */
249 sar eax, cl /* Signed shift mantissa according to exponent */
250
251 pop ebp /* Return */
252 ret 4
253
254 GetLong2:
255 xor eax, eax /* Overflow, return 0 */
256 pop ebp
257 ret 4
258
259
260 /******************************************************************************
261 * BOOL
262 * APIENTRY
263 * FLOATOBJ_Equal(IN PFLOATOBJ pf1, IN PFLOATOBJ pf2);
264 */
265 _FLOATOBJ_Equal@8:
266 PUBLIC _FLOATOBJ_Equal@8
267 push ebp
268 mov ebp, esp
269
270 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
271 mov eax, [esp + PARAM2] /* Load pf2 into ecx */
272
273 mov edx, [ecx + lExp] /* Get float1 in ecx, edx */
274 mov ecx, [ecx + lMant]
275
276 sub edx, [eax + lExp] /* Calculate diference to float2 */
277 sub ecx, [eax + lMant]
278
279 or edx, ecx /* Combine */
280
281 mov eax, 0 /* Set eax if combination is 0 */
282 setz al
283
284 pop ebp /* Return */
285 ret 8
286
287
288 /******************************************************************************
289 * BOOL
290 * APIENTRY
291 * FLOATOBJ_EqualLong(IN PFLOATOBJ pf, IN LONG l);
292 */
293 _FLOATOBJ_EqualLong@8:
294 PUBLIC _FLOATOBJ_EqualLong@8
295 push ebp
296 mov ebp, esp
297
298 mov eax, [esp + PARAM1] /* Load pf into eax */
299 mov ecx, 32 /* Load (32 - lExp) into ecx */
300 sub ecx, [eax + lExp]
301 mov edx, [eax + lMant] /* Load mantissa into edx */
302 sar edx, cl /* Signed shift mantissa according to exponent */
303 shl edx, cl /* Shift the mantissa back */
304 cmp edx, [eax + lMant] /* Check whether bits were killed by shifting */
305 jnz EqualLongFalse /* We have truncated the mantissa, return 0 */
306
307 sar edx, cl /* Shift the mantissa again */
308 xor eax, eax /* Set return value ... */
309 cmp edx, [esp + PARAM2] /* TRUE if shifted mantissa equals the LONG */
310 setz al
311
312 pop ebp /* Return */
313 ret 8
314
315 EqualLongFalse:
316 xor eax, eax /* Return FALSE */
317 pop ebp
318 ret 8
319
320
321 /******************************************************************************
322 * BOOL
323 * APIENTRY
324 * FLOATOBJ_GreaterThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1);
325 *
326 */
327 _FLOATOBJ_GreaterThan@8:
328 PUBLIC _FLOATOBJ_GreaterThan@8
329 push ebp
330 mov ebp, esp
331
332 mov eax, [ebp + PARAM1] /* Load pointer to efloat1 in eax */
333 mov edx, [ebp + PARAM2] /* Load pointer to efloat2 in edx */
334
335 mov ecx, [eax + lMant] /* Load mantissa1 in ecx */
336 mov edx, [edx + lMant] /* Load mantissa2 in edx */
337
338 sar ecx, 31 /* Calculate sign(lMant1) in ecx */
339 sar edx, 31 /* Calculate sign(lMant2) in edx */
340
341 cmp ecx, edx /* Branch if both have the same sign */
342 je GreaterThan_2
343
344 /* Mantissae have different sign */
345 mov eax, 0 /* Return (sign(lMant1) > sign(lMant2)) */
346 setg al
347 pop ebp
348 ret 8
349
350 GreaterThan_2:
351 /* Mantissae have the same sign */
352
353 mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */
354 test ecx, ecx /* Branch if sign is negative */
355 js GreaterThan_neg
356
357 /* Both mantissae are positive or 0 */
358
359 or ecx, [edx + lMant] /* Branch if one mantissa is 0 */
360 jz GreaterThan_pos2
361
362 /* Both mantissae are positive */
363
364 mov ecx, [eax + lExp] /* Branch if exponents are equal */
365 cmp ecx, [edx + lExp]
366 je GreaterThan_pos2
367
368 mov eax, 0 /* Return (lExp1 > lExp2) */
369 setg al
370 pop ebp
371 ret 8
372
373 GreaterThan_pos2:
374 /* Exponents are equal or one mantissa is 0 */
375
376 mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */
377 cmp ecx, [edx + lMant]
378 mov eax, 0
379 setg al
380 pop ebp
381 ret 8
382
383 GreaterThan_neg:
384 /* Both mantissae are negative */
385
386 mov ecx, [eax + lExp] /* Branch if exponents are equal */
387 cmp ecx, [edx + lExp]
388 je GreaterThan_neg2
389
390 /* Both mantissae negative, exponents are different */
391
392 mov eax, 0 /* Return (lExp1 < lExp2) */
393 setl al
394 pop ebp
395 ret 8
396
397 GreaterThan_neg2:
398 /* Both mantissae negative, exponents are equal */
399
400 mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */
401 cmp ecx, [edx + lMant]
402 mov eax, 0
403 setl al
404 pop ebp
405 ret 8
406
407
408
409 /******************************************************************************
410 * VOID
411 * APIENTRY
412 * FLOATOBJ_GreaterThanLong(IN OUT PFLOATOBJ pf, IN LONG l);
413 *
414 * Currently implemented as a wrapper around FLOATOBJ_SetLong and
415 * LOATOBJ_GreaterThan
416 */
417 _FLOATOBJ_GreaterThanLong@8:
418 PUBLIC _FLOATOBJ_GreaterThanLong@8
419 push ebp
420 mov ebp, esp
421
422 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
423 mov eax, [ebp + PARAM2] /* Load LONG into eax */
424
425 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
426
427 push eax /* Push LONG on the stack */
428 push ecx /* Push pointer to local FLOATOBJ on the stack */
429 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
430
431 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
432 push ecx
433 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
434 call _FLOATOBJ_GreaterThan@8 /* Compare */
435
436 mov esp, ebp /* Cleanup and return */
437 pop ebp
438 ret 8
439
440
441 /******************************************************************************
442 * BOOL
443 * APIENTRY
444 * FLOATOBJ_LessThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1);
445 *
446 */
447 _FLOATOBJ_LessThan@8:
448 PUBLIC _FLOATOBJ_LessThan@8
449 push ebp
450 mov ebp, esp
451
452 mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and edx */
453 mov edx, [ebp + PARAM2]
454
455 mov ecx, [eax + lMant] /* Load mantissae in ecx and edx */
456 mov edx, [edx + lMant]
457
458 sar ecx, 31 /* Calculate sign(lMant1) and sign(lMant2) */
459 sar edx, 31
460
461 cmp ecx, edx /* Branch if both have the same sign */
462 je LessThan_2
463
464 /* Mantissae have different sign */
465
466 mov eax, 0 /* Return (sign(lMant1) < sign(lMant2)) */
467 setl al
468 pop ebp
469 ret 8
470
471 LessThan_2:
472 /* Mantissae have the same sign */
473
474
475 mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */
476
477 test ecx, ecx /* Branch if sign is negative */
478 js LessThan_neg
479
480 /* Both mantissae are positive or 0 */
481
482 or ecx, [edx + lMant] /* Branch if one mantissa is 0 */
483 jz LessThan_pos2
484
485 /* Both mantissae are positive */
486
487 mov ecx, [eax + lExp] /* Branch if exponents are equal */
488 cmp ecx, [edx + lExp]
489 je LessThan_pos2
490
491 mov eax, 0 /* Return (lExp1 < lExp2) */
492 setl al
493 pop ebp
494 ret 8
495
496 LessThan_pos2:
497 /* Exponents are equal or one mantissa is 0 */
498
499 mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */
500 cmp ecx, [edx + lMant]
501 mov eax, 0
502 setl al
503 pop ebp
504 ret 8
505
506 LessThan_neg:
507 /* Both mantissae are negative */
508
509 mov ecx, [eax + lExp] /* Branch if exponents are equal */
510 cmp ecx, [edx + lExp]
511 je LessThan_neg2
512
513 /* Both mantissae negative, exponents are different */
514
515 mov eax, 0 /* Return (lExp1 > lExp2) */
516 setg al
517 pop ebp
518 ret 8
519
520 LessThan_neg2:
521 /* Both mantissae negative, exponents are equal */
522
523 mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */
524 cmp ecx, [edx + lMant]
525 mov eax, 0
526 setg al
527 pop ebp
528 ret 8
529
530
531 /******************************************************************************
532 * VOID
533 * APIENTRY
534 * FLOATOBJ_LessThanLong(IN OUT PFLOATOBJ pf, IN LONG l);
535 *
536 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_LessThan
537 */
538 _FLOATOBJ_LessThanLong@8:
539 PUBLIC _FLOATOBJ_LessThanLong@8
540 push ebp
541 mov ebp, esp
542
543 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
544 mov eax, [ebp + PARAM2] /* Load LONG into eax */
545
546 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
547 push eax /* Push LONG on the stack */
548 push ecx /* Push pointer to local FLOATOBJ on the stack */
549 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
550
551 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
552 push ecx
553 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
554 call _FLOATOBJ_LessThan@8 /* Compare */
555
556 mov esp, ebp /* Cleanup and return */
557 pop ebp
558 ret 8
559
560
561
562 /******************************************************************************
563 * VOID
564 * APIENTRY
565 * FLOATOBJ_Mul(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
566 *
567 * (mant1 * 2^exp1) * (mant2 * 2^exp2) = (mant1 * mant2) * 2^(exp1 + exp2)
568 * or mant = mant1 * mant2 and exp = exp1 + exp2
569 * No special handling for 0, where mantissa is 0
570 */
571 _FLOATOBJ_Mul@8:
572 PUBLIC _FLOATOBJ_Mul@8
573 push ebp
574 mov ebp, esp
575
576 mov edx, [esp + PARAM1] /* Load pf1 into edx */
577 mov ecx, [esp + PARAM2] /* Load pf2 into ecx */
578 mov eax, [ecx + lMant] /* Load mantissa2 into eax */
579 mov ecx, [ecx + lExp] /* Load exponent2 into ecx */
580
581 imul dword ptr [edx + lMant] /* Multiply eax with mantissa 1 */
582
583 test edx, edx /* Special handling for result < 0 */
584 js MulNeg
585
586 shl edx, 2 /* Get new mantissa from bits 30 to 62 */
587 shr eax, 30 /* of edx:eax into edx */
588 or eax, edx
589
590 mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */
591 mov ecx, 0 /* Check for highest bit */
592 sets cl
593 shr eax, cl /* Normalize mantissa in eax */
594
595 jz Mul0 /* All 0? */
596
597 lea edx, [edx + ecx -2] /* Normalize exponent in edx */
598
599
600 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
601 mov [ecx + lMant], eax /* Save back mantissa */
602 add [ecx + lExp], edx /* Save back exponent */
603
604 pop ebp /* Return */
605 ret 8
606
607 MulNeg:
608
609 shl edx, 2 /* Get new mantissa from bits 30 to 62 */
610 shr eax, 30 /* of edx:eax into edx */
611 or eax, edx
612
613 mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */
614
615 mov ecx, 0 /* Check for highest bit */
616 setns cl
617 shr eax, cl /* Normalize mantissa in eax */
618
619 jz Mul0 /* All 0? */
620
621
622 lea edx, [edx + ecx -2] /* Normalize exponent in edx */
623 or eax, HEX(80000000) /* Set sign bit */
624
625 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
626 mov [ecx + lMant], eax /* Save back mantissa */
627 add [ecx + lExp], edx /* Save back exponent */
628
629 pop ebp /* Return */
630 ret 8
631
632 Mul0:
633 mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
634 mov [ecx + lMant], eax /* Store 0 in mantissa */
635 mov [ecx + lExp], eax /* Store 0 in exponent */
636
637 pop ebp /* Return */
638 ret 8
639
640
641 /******************************************************************************
642 * VOID
643 * APIENTRY
644 * FLOATOBJ_MulFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
645 *
646 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Mul
647 */
648 _FLOATOBJ_MulFloat@8:
649 PUBLIC _FLOATOBJ_MulFloat@8
650 push ebp
651 mov ebp, esp
652
653 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
654 mov eax, [ebp + PARAM2] /* Load f into eax */
655 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
656 push eax /* Push f on the stack */
657 push ecx /* Push pointer to local FLOATOBJ on the stack */
658 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
659
660 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
661 push ecx
662 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
663 call _FLOATOBJ_Mul@8 /* Multiply */
664
665 mov esp, ebp /* Cleanup and return */
666 pop ebp
667 ret 8
668
669
670 /******************************************************************************
671 * VOID
672 * APIENTRY
673 * FLOATOBJ_MulLong(IN OUT PFLOATOBJ pf, IN LONG l);
674 *
675 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Mul
676 */
677 _FLOATOBJ_MulLong@8:
678 PUBLIC _FLOATOBJ_MulLong@8
679 push ebp
680 mov ebp, esp
681
682 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
683 mov eax, [ebp + PARAM2] /* Load l into eax */
684 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
685 push eax /* Push l on the stack */
686 push ecx /* Push pointer to local FLOATOBJ on the stack */
687 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
688
689 lea ecx, [ebp -8] /* Push pointer to local FLOATOBJ on the stack */
690 push ecx
691 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
692 call _FLOATOBJ_Mul@8 /* Multiply */
693
694 mov esp, ebp /* Cleanup and return */
695 pop ebp
696 ret 8
697
698
699 /*******************************************************************************
700 * VOID
701 * APIENTRY
702 * FLOATOBJ_Div(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
703 *
704 */
705 _FLOATOBJ_Div@8:
706 PUBLIC _FLOATOBJ_Div@8
707 push ebp
708 mov ebp, esp
709 push ebx
710
711 mov eax, [ebp + PARAM2] /* Load lMant2 into eax */
712 mov eax, [eax + lMant]
713
714 cdq /* Calculate abs(lMant2) */
715 xor eax, edx
716 sub eax, edx
717 jz DivError /* Divide by zero error! */
718
719 mov ebx, edx /* Copy sign(lMant2) to ebx */
720 mov ecx, eax /* Copy abs(lMant2) to ecx */
721
722 mov eax, [ebp + PARAM1] /* Load lMant1 into eax */
723 mov eax, [eax + lMant]
724
725 cdq /* Calculate abs(lMant1) */
726 xor eax, edx
727 sub eax, edx
728
729 jz Div0 /* Dividend is 0? */
730
731 xor ebx, edx /* combine both signs in ebx */
732
733 mov edx, eax /* Prepare edx:eax for integer divide */
734 xor eax, eax
735 shr edx, 1
736 div ecx /* Do an unsigned divide */
737
738 xor ecx, ecx /* Adjust result */
739 test eax, HEX(80000000)
740 setnz cl
741 shr eax, cl
742
743 xor eax, ebx /* Correct the result's sign */
744 sub eax, ebx
745
746 mov edx, [ebp + PARAM1] /* Load pf1 into edx */
747 mov [edx + lMant], eax /* Safe back the mantissa */
748 mov ebx, [ebp + PARAM2] /* Load pf2 into ebx */
749 sub ecx, [ebx + lExp] /* Calculate exponent offset */
750 inc ecx
751 add [edx + lExp], ecx /* Safe back exponent */
752
753 pop ebx /* Return */
754 pop ebp
755 ret 8
756
757 DivError:
758 Div0:
759 mov edx, [ebp + PARAM1] /* Load pf into edx */
760 mov [edx + lMant], eax /* Store 0 in mantissa */
761 mov [edx + lExp], eax /* Store 0 in exponent */
762
763 pop ebx /* Return */
764 pop ebp
765 ret 8
766
767
768 /******************************************************************************
769 * VOID
770 * APIENTRY
771 * FLOATOBJ_DivFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
772 *
773 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Div
774 */
775 _FLOATOBJ_DivFloat@8:
776 PUBLIC _FLOATOBJ_DivFloat@8
777 push ebp
778 mov ebp, esp
779 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
780
781 mov eax, [ebp + PARAM2] /* Load f into eax */
782 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
783 push eax /* Push f on the stack */
784 push ecx /* Push pointer to local FLOATOBJ on the stack */
785 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
786
787 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
788 push ecx
789 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
790 call _FLOATOBJ_Div@8 /* Divide */
791
792 mov esp, ebp /* Cleanup and return */
793 pop ebp
794 ret 8
795
796
797 /******************************************************************************
798 * VOID
799 * APIENTRY
800 * FLOATOBJ_DivLong(IN OUT PFLOATOBJ pf, IN LONG l);
801 *
802 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Div
803 */
804 _FLOATOBJ_DivLong@8:
805 PUBLIC _FLOATOBJ_DivLong@8
806 push ebp
807 mov ebp, esp
808 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
809
810 mov eax, [ebp + PARAM2] /* Load l into eax */
811 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
812 push eax /* Push l on the stack */
813 push ecx /* Push pointer to local FLOATOBJ on the stack */
814 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
815
816 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
817 push ecx
818 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
819 call _FLOATOBJ_Div@8 /* Divide */
820
821 mov esp, ebp /* Cleanup and return */
822 pop ebp
823 ret 8
824
825
826 /*******************************************************************************
827 * VOID
828 * APIENTRY
829 * FLOATOBJ_Add(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
830 *
831 */
832 _FLOATOBJ_Add@8:
833 PUBLIC _FLOATOBJ_Add@8
834 push ebp
835 mov ebp, esp
836 push ebx
837
838 mov eax, [ebp + PARAM1] /* Load pointer to pf1 in eax */
839 mov ebx, [ebp + PARAM2] /* Load pointer to pf2 in ebx */
840
841 mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) */
842 mov edx, [ebx + lExp]
843 mov eax, [eax + lMant] /* Load float2 in (ebx,edx) */
844 mov ebx, [ebx + lMant]
845
846 cmp ecx, edx /* Check which one has the bigger lExp */
847 jl Add2
848
849 sub ecx, edx /* Calculate lExp1 - lExp2 */
850 sar eax, 1 /* Shift both mantissae 1 bit right */
851 sar ebx, 1
852 sar ebx, cl /* Shift lMant2 according to exponent difference */
853
854 add eax, ebx /* Add the manrissae */
855 jz AddIs0
856
857 cdq /* Calculate abs(mantissa) */
858 xor eax, edx
859 sub eax, edx
860
861 bsr ecx, eax /* Find most significant bit */
862 neg ecx /* and calculate needed normalize shift */
863 add ecx, 30
864 shl eax, cl
865 dec ecx
866
867 xor eax, edx /* Go back to original sign */
868 sub eax, edx
869
870 mov edx, [ebp + PARAM1] /* Reload pointer to float1 */
871
872 pop ebx
873
874 mov dword ptr [edx + lMant], eax /* Safe mantissa */
875 sub [edx + lExp], ecx /* Adjust exponent */
876
877 pop ebp /* Return */
878 ret 8
879
880 Add2:
881 sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */
882 mov ecx, edx
883
884 sar ebx, 1 /* Shift both mantissae 1 bit right */
885 sar eax, 1
886 sar eax, cl /* Shift lMant2 according to exponent difference */
887
888 add eax, ebx /* Add the manrissae */
889 jz AddIs0
890
891 mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */
892 add [ebx + lExp], ecx /* Adjust exponent part 1 */
893
894 cdq /* Calculate abs(mantissa) */
895 xor eax, edx
896 sub eax, edx
897
898 bsr ecx, eax /* Find most significant bit */
899 neg ecx /* and calculate needed normalize shift */
900 add ecx, 30
901 shl eax, cl
902 dec ecx
903
904 xor eax, edx /* Go back to original sign */
905 sub eax, edx
906
907 mov dword ptr [ebx + lMant], eax /* Safe mantissa and adjust exponent */
908 sub [ebx + lExp], ecx
909
910 pop ebx /* Return */
911 pop ebp
912 ret 8
913
914 AddIs0:
915 /* Mantissa is 0, so float to (0,0) */
916 mov eax, [ebp + PARAM1]
917 pop ebx
918 mov dword ptr [eax + lMant], 0
919 mov dword ptr [eax + lExp], 0
920 pop ebp
921 ret 8
922
923
924 /******************************************************************************
925 * VOID
926 * APIENTRY
927 * FLOATOBJ_AddFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
928 *
929 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Add
930 */
931 _FLOATOBJ_AddFloat@8:
932 PUBLIC _FLOATOBJ_AddFloat@8
933 push ebp
934 mov ebp, esp
935 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
936
937 mov eax, [ebp + PARAM2] /* Load f into eax */
938 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
939 push eax /* Push f on the stack */
940 push ecx /* Push pointer to local FLOATOBJ on the stack */
941 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
942
943 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
944 push ecx
945 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
946 call _FLOATOBJ_Add@8 /* Add */
947
948 mov esp, ebp /* Cleanup and return */
949 pop ebp
950 ret 8
951
952
953 /******************************************************************************
954 * VOID
955 * APIENTRY
956 * FLOATOBJ_AddLong(IN OUT PFLOATOBJ pf, IN LONG l);
957 *
958 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Add
959 */
960 _FLOATOBJ_AddLong@8:
961 PUBLIC _FLOATOBJ_AddLong@8
962 push ebp
963 mov ebp, esp
964 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
965
966 mov eax, [ebp + PARAM2] /* Load l into eax */
967 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
968 push eax /* Push l on the stack */
969 push ecx /* Push pointer to local FLOATOBJ on the stack */
970 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
971
972 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
973 push ecx
974 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
975 call _FLOATOBJ_Add@8 /* Add */
976
977 mov esp, ebp /* Cleanup and return */
978 pop ebp
979 ret 8
980
981
982 /*******************************************************************************
983 * VOID
984 * APIENTRY
985 * FLOATOBJ_Sub(IN OUT PFLOATOBJ pf, IN PFLOATOBJ pf1);
986 *
987 */
988 _FLOATOBJ_Sub@8:
989 PUBLIC _FLOATOBJ_Sub@8
990 push ebp
991 mov ebp, esp
992 push ebx
993
994 mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and ebx */
995 mov ebx, [ebp + PARAM2]
996
997 mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) and float2 in (ebx,edx) */
998 mov edx, [ebx + lExp]
999 mov eax, [eax + lMant]
1000 mov ebx, [ebx + lMant]
1001
1002 cmp ecx, edx /* Check which one has the bigger lExp */
1003 jl Sub2
1004
1005 sub ecx, edx /* Calculate lExp1 - lExp2 */
1006 sar eax, 1 /* Shift both mantissae 1 bit right */
1007 sar ebx, 1
1008 sar ebx, cl /* Shift lMant2 according to exponent difference */
1009
1010 sub eax, ebx /* Substract the manrissae */
1011 jz SubIs0
1012
1013 cdq /* Calculate abs(mantissa) */
1014 xor eax, edx
1015 sub eax, edx
1016
1017 bsr ecx, eax /* Find most significant bit */
1018 neg ecx /* and calculate needed normalize shift */
1019 add ecx, 30
1020 shl eax, cl
1021 dec ecx
1022
1023 xor eax, edx /* Go back to original sign */
1024 sub eax, edx
1025
1026 mov edx, [ebp + PARAM1] /* Reload pointer to float1 */
1027
1028 pop ebx
1029
1030 mov dword ptr [edx + lMant], eax /* Safe mantissa and adjust exponent */
1031 sub [edx + lExp], ecx
1032
1033 pop ebp
1034 ret 8
1035
1036 Sub2:
1037 sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */
1038 mov ecx, edx
1039
1040 sar ebx, 1 /* Shift both mantissae 1 bit right */
1041 sar eax, 1
1042 sar eax, cl /* Shift lMant2 according to exponent difference */
1043
1044 sub eax, ebx /* Substract the manrissae */
1045 jz AddIs0
1046
1047 mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */
1048 add [ebx + lExp], ecx /* Adjust exponent part 1 */
1049
1050 cdq /* Calculate abs(mantissa) */
1051 xor eax, edx
1052 sub eax, edx
1053
1054 bsr ecx, eax /* Find most significant bit */
1055 neg ecx /* and calculate needed normalize shift */
1056 add ecx, 30
1057 shl eax, cl
1058 dec ecx
1059
1060 xor eax, edx /* Go back to original sign */
1061 sub eax, edx
1062
1063 mov dword ptr [ebx + lMant], eax /* Safe mantissa */
1064 sub [ebx + lExp], ecx /* Adjust exponent */
1065
1066 pop ebx /* Return */
1067 pop ebp
1068 ret 8
1069
1070 SubIs0:
1071 /* Mantissa is 0, so float to (0,0) */
1072 mov eax, [ebp + PARAM1]
1073 pop ebx
1074 mov dword ptr [eax + lMant], 0
1075 mov dword ptr [eax + lExp], 0
1076 pop ebp
1077 ret 8
1078
1079 /******************************************************************************
1080 * VOID
1081 * APIENTRY
1082 * FLOATOBJ_SubFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
1083 *
1084 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Sub
1085 */
1086 _FLOATOBJ_SubFloat@8:
1087 PUBLIC _FLOATOBJ_SubFloat@8
1088 push ebp
1089 mov ebp, esp
1090 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
1091
1092 mov eax, [ebp + PARAM2] /* Load f into eax */
1093 lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
1094 push eax /* Push f on the stack */
1095 push ecx /* Push pointer to local FLOATOBJ on the stack */
1096 call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
1097
1098 lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
1099 push ecx
1100 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
1101 call _FLOATOBJ_Sub@8 /* Substract */
1102
1103 mov esp, ebp /* Cleanup and return */
1104 pop ebp
1105 ret 8
1106
1107
1108 /******************************************************************************
1109 * VOID
1110 * APIENTRY
1111 * FLOATOBJ_SubLong(IN OUT PFLOATOBJ pf, IN LONG l);
1112 *
1113 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Sub
1114 */
1115 _FLOATOBJ_SubLong@8:
1116 PUBLIC _FLOATOBJ_SubLong@8
1117 push ebp
1118 mov ebp, esp
1119 sub esp, 8 /* Make room for a FLOATOBJ on the stack */
1120
1121 mov eax, [ebp + PARAM2] /* Load l into eax */
1122 lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
1123 push eax /* Push l on the stack */
1124 push ecx /* Push pointer to local FLOATOBJ on the stack */
1125 call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
1126
1127 lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
1128 push ecx
1129 push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
1130 call _FLOATOBJ_Sub@8 /* Substract */
1131
1132 mov esp, ebp /* Cleanup and return */
1133 pop ebp
1134 ret 8
1135
1136
1137 /*******************************************************************************
1138 * VOID
1139 * APIENTRY
1140 * FLOATOBJ_Neg(IN OUT PFLOATOBJ pf);
1141 *
1142 */
1143 _FLOATOBJ_Neg@4:
1144 PUBLIC _FLOATOBJ_Neg@4
1145 push ebp
1146 mov ebp, esp
1147
1148 mov ecx, [esp + PARAM1] /* Load pf into ecx */
1149 neg dword ptr [ecx + lMant] /* Negate lMant1 */
1150
1151 pop ebp /* Return */
1152 ret 4
1153
1154 END
1155 /* EOF */