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