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