/* * COPYRIGHT: LGPL, see LGPL.txt in the top level directory * PROJECT: ReactOS Win32 subsystem * PURPOSE: FLOATOBJ floating point emulation functions for x86 * FILE: win32ss/gdi/eng/i386/floatobj.S * PROGRAMMER: Timo Kreuzer */ #include .code /******************************************************************************* * IEEE 754-1985 single precision floating point * * | 31 | 30...23 | 22...0 | * |sign| exponent | fraction | * * mantissa = 1 + (fraction / 2^23) * f = (-1)^sign * mantissa * 2 ^ (exponent - bias) * bias = 127 * ******************************************************************************* * win32k x86 floating point emulation * * struct _EFLOAT = { * LONG lMant; * LONG lExp; * }; * * f = (lMant / 0x40000000) * 2 ^ (lExp - 2) * = lMant * 2 ^ (lExp - 32) * ******************************************************************************* * Optimization notes: * * - shld is slow (4 cycles) and not pairable, mov + shl is faster * - esp is used, because it's available earlier * - bsr is very slow on old cpus (up to 72 cycles on a p1) while being much * faster on modern cpus (2-11 cycles). Workarounds using branch trees or * table lookups are of no use nowadays. ******************************************************************************* * Compatibility notes: * - There are issues with very large size values near integer overflow. * Floating point values are behaving different there. This behavior isn't * simulated yet. Difference is < 10^-5 % * - The result of a multiplication can differ from Windows result in the * least significant bit, that is a difference of 1 / 2^30 or ~10^-9 ******************************************************************************* * Implementation status: * * FLOATOBJ_SetFloat - implemented, tested * FLOATOBJ_SetLong - implemented, tested * FLOATOBJ_GetFloat - implemented, tested * FLOATOBJ_GetLong - implemented, tested * FLOATOBJ_Equal - implemented, tested * FLOATOBJ_EqualLong - implemented * FLOATOBJ_GreaterThan - implemented * FLOATOBJ_GreaterThanLong - wrapper * FLOATOBJ_LessThan - implemented * FLOATOBJ_LessThanLong - wrapper * FLOATOBJ_Neg - implemented * FLOATOBJ_Mul - implemented, tested, optimized * FLOATOBJ_MulFloat - wrapper * FLOATOBJ_MulLong - wrapper, could really need optimization * FLOATOBJ_Div - implemented * FLOATOBJ_DivFloat - wrapper * FLOATOBJ_DivLong - wrapper * FLOATOBJ_Add - implemented, tested * FLOATOBJ_AddFloat - wrapper * FLOATOBJ_AddLong - wrapper * FLOATOBJ_Sub - implemented, tested * FLOATOBJ_SubFloat - wrapper * FLOATOBJ_SubLong - wrapper */ #define lMant 0 #define lExp 4 #define PARAM1 8 #define PARAM2 12 /** Globals **/ /* extern const FLOATOBJ gef0; */ PUBLIC _gef0 _gef0: .long 0, 0 /* extern const FLOATOBJ gef1; */ PUBLIC _gef1 _gef1: .long HEX(40000000), HEX(00000002) /* extern const FLOATOBJ gef16; */ PUBLIC _gef16 _gef16: .long HEX(40000000), HEX(00000006) /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_SetFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); */ _FLOATOBJ_SetFloat@8: PUBLIC _FLOATOBJ_SetFloat@8 push ebp mov ebp, esp mov ecx, [esp + PARAM2] /* Load the float into ecx */ mov eax, ecx /* Copy float to eax for later */ test ecx, HEX(7f800000) /* Check for zero exponent - 0 or denormal */ jz SetFloat0 /* If it's all zero, ... */ shl ecx, 7 /* Put the bits for the mantissa in place */ cdq /* Fill edx with the sign from the FLOATL in eax */ and ecx, HEX(7fffffff) /* Mask out invalid field in the mantissa */ shr eax, 23 /* Shift the exponent in eax in place */ or ecx, HEX(40000000) /* Set bit for 1 in the mantissa */ and eax, HEX(0ff) /* Mask out invalid fields in the exponent in eax */ xor ecx, edx /* Make use of the sign bit expanded to full edx */ sub eax, 125 /* Adjust exonent bias */ sub ecx, edx /* Substract -1 or add 1 if sign was set */ mov edx, [esp + PARAM1] /* Load pf into edx */ mov [edx + lMant], ecx /* Save back mantissa */ mov [edx + lExp], eax /* Save back exponent */ pop ebp /* Return */ ret 8 SetFloat0: mov edx, [esp + PARAM1] /* Load pf into edx */ mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */ mov dword ptr [edx + lExp], 0 pop ebp /* Return */ ret 8 /******************************************************************************* * LONG * APIENTRY * FLOATOBJ_GetFloat(IN PFLOATOBJ pf); * */ _FLOATOBJ_GetFloat@4: PUBLIC _FLOATOBJ_GetFloat@4 push ebp mov ebp, esp mov edx, [esp + PARAM1] /* Load pf into edx */ mov eax, [edx + lMant] /* Load mantissa into eax */ mov ecx, [edx + lExp] /* Load exponent into ecx */ cdq /* Calculate abs(mantissa) */ xor eax, edx add ecx, 125 sub eax, edx jz GetFloatRet and ecx, HEX(0ff) /* Mask out invalid fields in the exponent */ and eax, HEX(3fffffff) /* Mask out invalid fields in mantissa */ shl ecx, 23 /* Shift exponent in place */ shr eax, 7 /* Shift mantissa in place */ and edx, HEX(80000000) /* Reduce edx to sign bit only */ or eax, ecx /* Set exponent in result */ or eax, edx /* Set sign bit in result */ GetFloatRet: /* Return */ pop ebp ret 4 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_SetLong(OUT PFLOATOBJ pf, IN LONG l); * * Instead of using abs(l), which is 3 + 2 instructions, use a branch. */ _FLOATOBJ_SetLong@8: PUBLIC _FLOATOBJ_SetLong@8 push ebp mov ebp, esp mov eax, [esp + PARAM2] /* Load l into eax */ mov edx, [esp + PARAM1] /* Load pf into edx */ test eax, eax /* different handling for <0, =0 and >0 */ js SetLongNeg jz SetLong0 bsr ecx, eax /* Get number of most significant bit aka log2(l) */ mov [edx + lExp], ecx /* Safe log2(l) into exponent */ neg ecx /* Calculate necessary shift */ add ecx, 30 add dword ptr [edx + lExp], 2 /* Adjust exponent */ shl eax, cl /* Shift mantissa in place */ mov [edx + lMant], eax /* Save mantissa */ pop ebp /* Return */ ret 8 SetLongNeg: neg eax /* Get absolute value of l */ bsr ecx, eax /* Get number of most significant bit aka log2(l) */ neg eax /* Back to negative */ mov [edx + lExp], ecx /* Safe log2(-l) into exponent */ neg ecx /* Calculate necessary shift */ add ecx, 30 add dword ptr [edx + lExp], 2 /* Adjust exponent */ shl eax, cl /* Shift mantissa in place */ mov [edx + lMant], eax /* Save mantissa */ pop ebp /* Return */ ret 8 SetLong0: mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */ mov dword ptr [edx + lExp], 0 pop ebp /* Return */ ret 8 /******************************************************************************* * LONG * APIENTRY * FLOATOBJ_GetLong(IN PFLOATOBJ pf); * */ _FLOATOBJ_GetLong@4: PUBLIC _FLOATOBJ_GetLong@4 push ebp mov ebp, esp mov edx, [ebp + PARAM1] /* Load pf into edx */ mov ecx, 32 /* Load (32 - lExp) into ecx */ sub ecx, [edx + lExp] jle short GetLong2 /* Check for Overflow */ mov eax, [edx + lMant] /* Load mantissa into eax */ sar eax, cl /* Signed shift mantissa according to exponent */ pop ebp /* Return */ ret 4 GetLong2: xor eax, eax /* Overflow, return 0 */ pop ebp ret 4 /****************************************************************************** * BOOL * APIENTRY * FLOATOBJ_Equal(IN PFLOATOBJ pf1, IN PFLOATOBJ pf2); */ _FLOATOBJ_Equal@8: PUBLIC _FLOATOBJ_Equal@8 push ebp mov ebp, esp mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ mov eax, [esp + PARAM2] /* Load pf2 into ecx */ mov edx, [ecx + lExp] /* Get float1 in ecx, edx */ mov ecx, [ecx + lMant] sub edx, [eax + lExp] /* Calculate diference to float2 */ sub ecx, [eax + lMant] or edx, ecx /* Combine */ mov eax, 0 /* Set eax if combination is 0 */ setz al pop ebp /* Return */ ret 8 /****************************************************************************** * BOOL * APIENTRY * FLOATOBJ_EqualLong(IN PFLOATOBJ pf, IN LONG l); */ _FLOATOBJ_EqualLong@8: PUBLIC _FLOATOBJ_EqualLong@8 push ebp mov ebp, esp mov eax, [esp + PARAM1] /* Load pf into eax */ mov ecx, 32 /* Load (32 - lExp) into ecx */ sub ecx, [eax + lExp] mov edx, [eax + lMant] /* Load mantissa into edx */ sar edx, cl /* Signed shift mantissa according to exponent */ shl edx, cl /* Shift the mantissa back */ cmp edx, [eax + lMant] /* Check whether bits were killed by shifting */ jnz EqualLongFalse /* We have truncated the mantissa, return 0 */ sar edx, cl /* Shift the mantissa again */ xor eax, eax /* Set return value ... */ cmp edx, [esp + PARAM2] /* TRUE if shifted mantissa equals the LONG */ setz al pop ebp /* Return */ ret 8 EqualLongFalse: xor eax, eax /* Return FALSE */ pop ebp ret 8 /****************************************************************************** * BOOL * APIENTRY * FLOATOBJ_GreaterThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1); * */ _FLOATOBJ_GreaterThan@8: PUBLIC _FLOATOBJ_GreaterThan@8 push ebp mov ebp, esp mov eax, [ebp + PARAM1] /* Load pointer to efloat1 in eax */ mov edx, [ebp + PARAM2] /* Load pointer to efloat2 in edx */ mov ecx, [eax + lMant] /* Load mantissa1 in ecx */ mov edx, [edx + lMant] /* Load mantissa2 in edx */ sar ecx, 31 /* Calculate sign(lMant1) in ecx */ sar edx, 31 /* Calculate sign(lMant2) in edx */ cmp ecx, edx /* Branch if both have the same sign */ je GreaterThan_2 /* Mantissae have different sign */ mov eax, 0 /* Return (sign(lMant1) > sign(lMant2)) */ setg al pop ebp ret 8 GreaterThan_2: /* Mantissae have the same sign */ mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */ test ecx, ecx /* Branch if sign is negative */ js GreaterThan_neg /* Both mantissae are positive or 0 */ or ecx, [edx + lMant] /* Branch if one mantissa is 0 */ jz GreaterThan_pos2 /* Both mantissae are positive */ mov ecx, [eax + lExp] /* Branch if exponents are equal */ cmp ecx, [edx + lExp] je GreaterThan_pos2 mov eax, 0 /* Return (lExp1 > lExp2) */ setg al pop ebp ret 8 GreaterThan_pos2: /* Exponents are equal or one mantissa is 0 */ mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */ cmp ecx, [edx + lMant] mov eax, 0 setg al pop ebp ret 8 GreaterThan_neg: /* Both mantissae are negative */ mov ecx, [eax + lExp] /* Branch if exponents are equal */ cmp ecx, [edx + lExp] je GreaterThan_neg2 /* Both mantissae negative, exponents are different */ mov eax, 0 /* Return (lExp1 < lExp2) */ setl al pop ebp ret 8 GreaterThan_neg2: /* Both mantissae negative, exponents are equal */ mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */ cmp ecx, [edx + lMant] mov eax, 0 setl al pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_GreaterThanLong(IN OUT PFLOATOBJ pf, IN LONG l); * * Currently implemented as a wrapper around FLOATOBJ_SetLong and * LOATOBJ_GreaterThan */ _FLOATOBJ_GreaterThanLong@8: PUBLIC _FLOATOBJ_GreaterThanLong@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load LONG into eax */ lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push LONG on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_GreaterThan@8 /* Compare */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /****************************************************************************** * BOOL * APIENTRY * FLOATOBJ_LessThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1); * */ _FLOATOBJ_LessThan@8: PUBLIC _FLOATOBJ_LessThan@8 push ebp mov ebp, esp mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and edx */ mov edx, [ebp + PARAM2] mov ecx, [eax + lMant] /* Load mantissae in ecx and edx */ mov edx, [edx + lMant] sar ecx, 31 /* Calculate sign(lMant1) and sign(lMant2) */ sar edx, 31 cmp ecx, edx /* Branch if both have the same sign */ je LessThan_2 /* Mantissae have different sign */ mov eax, 0 /* Return (sign(lMant1) < sign(lMant2)) */ setl al pop ebp ret 8 LessThan_2: /* Mantissae have the same sign */ mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */ test ecx, ecx /* Branch if sign is negative */ js LessThan_neg /* Both mantissae are positive or 0 */ or ecx, [edx + lMant] /* Branch if one mantissa is 0 */ jz LessThan_pos2 /* Both mantissae are positive */ mov ecx, [eax + lExp] /* Branch if exponents are equal */ cmp ecx, [edx + lExp] je LessThan_pos2 mov eax, 0 /* Return (lExp1 < lExp2) */ setl al pop ebp ret 8 LessThan_pos2: /* Exponents are equal or one mantissa is 0 */ mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */ cmp ecx, [edx + lMant] mov eax, 0 setl al pop ebp ret 8 LessThan_neg: /* Both mantissae are negative */ mov ecx, [eax + lExp] /* Branch if exponents are equal */ cmp ecx, [edx + lExp] je LessThan_neg2 /* Both mantissae negative, exponents are different */ mov eax, 0 /* Return (lExp1 > lExp2) */ setg al pop ebp ret 8 LessThan_neg2: /* Both mantissae negative, exponents are equal */ mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */ cmp ecx, [edx + lMant] mov eax, 0 setg al pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_LessThanLong(IN OUT PFLOATOBJ pf, IN LONG l); * * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_LessThan */ _FLOATOBJ_LessThanLong@8: PUBLIC _FLOATOBJ_LessThanLong@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load LONG into eax */ lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push LONG on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_LessThan@8 /* Compare */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_Mul(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); * * (mant1 * 2^exp1) * (mant2 * 2^exp2) = (mant1 * mant2) * 2^(exp1 + exp2) * or mant = mant1 * mant2 and exp = exp1 + exp2 * No special handling for 0, where mantissa is 0 */ _FLOATOBJ_Mul@8: PUBLIC _FLOATOBJ_Mul@8 push ebp mov ebp, esp mov edx, [esp + PARAM1] /* Load pf1 into edx */ mov ecx, [esp + PARAM2] /* Load pf2 into ecx */ mov eax, [ecx + lMant] /* Load mantissa2 into eax */ mov ecx, [ecx + lExp] /* Load exponent2 into ecx */ imul dword ptr [edx + lMant] /* Multiply eax with mantissa 1 */ test edx, edx /* Special handling for result < 0 */ js MulNeg shl edx, 2 /* Get new mantissa from bits 30 to 62 */ shr eax, 30 /* of edx:eax into edx */ or eax, edx mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */ mov ecx, 0 /* Check for highest bit */ sets cl shr eax, cl /* Normalize mantissa in eax */ jz Mul0 /* All 0? */ lea edx, [edx + ecx -2] /* Normalize exponent in edx */ mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ mov [ecx + lMant], eax /* Save back mantissa */ add [ecx + lExp], edx /* Save back exponent */ pop ebp /* Return */ ret 8 MulNeg: shl edx, 2 /* Get new mantissa from bits 30 to 62 */ shr eax, 30 /* of edx:eax into edx */ or eax, edx mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */ mov ecx, 0 /* Check for highest bit */ setns cl shr eax, cl /* Normalize mantissa in eax */ jz Mul0 /* All 0? */ lea edx, [edx + ecx -2] /* Normalize exponent in edx */ or eax, HEX(80000000) /* Set sign bit */ mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ mov [ecx + lMant], eax /* Save back mantissa */ add [ecx + lExp], edx /* Save back exponent */ pop ebp /* Return */ ret 8 Mul0: mov ecx, [esp + PARAM1] /* Load pf1 into ecx */ mov [ecx + lMant], eax /* Store 0 in mantissa */ mov [ecx + lExp], eax /* Store 0 in exponent */ pop ebp /* Return */ ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_MulFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); * * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Mul */ _FLOATOBJ_MulFloat@8: PUBLIC _FLOATOBJ_MulFloat@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load f into eax */ lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push f on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Mul@8 /* Multiply */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_MulLong(IN OUT PFLOATOBJ pf, IN LONG l); * * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Mul */ _FLOATOBJ_MulLong@8: PUBLIC _FLOATOBJ_MulLong@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load l into eax */ lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push l on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ lea ecx, [ebp -8] /* Push pointer to local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Mul@8 /* Multiply */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /******************************************************************************* * VOID * APIENTRY * FLOATOBJ_Div(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); * */ _FLOATOBJ_Div@8: PUBLIC _FLOATOBJ_Div@8 push ebp mov ebp, esp push ebx mov eax, [ebp + PARAM2] /* Load lMant2 into eax */ mov eax, [eax + lMant] cdq /* Calculate abs(lMant2) */ xor eax, edx sub eax, edx jz DivError /* Divide by zero error! */ mov ebx, edx /* Copy sign(lMant2) to ebx */ mov ecx, eax /* Copy abs(lMant2) to ecx */ mov eax, [ebp + PARAM1] /* Load lMant1 into eax */ mov eax, [eax + lMant] cdq /* Calculate abs(lMant1) */ xor eax, edx sub eax, edx jz Div0 /* Dividend is 0? */ xor ebx, edx /* combine both signs in ebx */ mov edx, eax /* Prepare edx:eax for integer divide */ xor eax, eax shr edx, 1 div ecx /* Do an unsigned divide */ xor ecx, ecx /* Adjust result */ test eax, HEX(80000000) setnz cl shr eax, cl xor eax, ebx /* Correct the result's sign */ sub eax, ebx mov edx, [ebp + PARAM1] /* Load pf1 into edx */ mov [edx + lMant], eax /* Safe back the mantissa */ mov ebx, [ebp + PARAM2] /* Load pf2 into ebx */ sub ecx, [ebx + lExp] /* Calculate exponent offset */ inc ecx add [edx + lExp], ecx /* Safe back exponent */ pop ebx /* Return */ pop ebp ret 8 DivError: Div0: mov edx, [ebp + PARAM1] /* Load pf into edx */ mov [edx + lMant], eax /* Store 0 in mantissa */ mov [edx + lExp], eax /* Store 0 in exponent */ pop ebx /* Return */ pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_DivFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); * * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Div */ _FLOATOBJ_DivFloat@8: PUBLIC _FLOATOBJ_DivFloat@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load f into eax */ lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push f on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Div@8 /* Divide */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_DivLong(IN OUT PFLOATOBJ pf, IN LONG l); * * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Div */ _FLOATOBJ_DivLong@8: PUBLIC _FLOATOBJ_DivLong@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load l into eax */ lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push l on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Div@8 /* Divide */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /******************************************************************************* * VOID * APIENTRY * FLOATOBJ_Add(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); * */ _FLOATOBJ_Add@8: PUBLIC _FLOATOBJ_Add@8 push ebp mov ebp, esp push ebx mov eax, [ebp + PARAM1] /* Load pointer to pf1 in eax */ mov ebx, [ebp + PARAM2] /* Load pointer to pf2 in ebx */ mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) */ mov edx, [ebx + lExp] mov eax, [eax + lMant] /* Load float2 in (ebx,edx) */ mov ebx, [ebx + lMant] cmp ecx, edx /* Check which one has the bigger lExp */ jl Add2 sub ecx, edx /* Calculate lExp1 - lExp2 */ sar eax, 1 /* Shift both mantissae 1 bit right */ sar ebx, 1 sar ebx, cl /* Shift lMant2 according to exponent difference */ add eax, ebx /* Add the manrissae */ jz AddIs0 cdq /* Calculate abs(mantissa) */ xor eax, edx sub eax, edx bsr ecx, eax /* Find most significant bit */ neg ecx /* and calculate needed normalize shift */ add ecx, 30 shl eax, cl dec ecx xor eax, edx /* Go back to original sign */ sub eax, edx mov edx, [ebp + PARAM1] /* Reload pointer to float1 */ pop ebx mov dword ptr [edx + lMant], eax /* Safe mantissa */ sub [edx + lExp], ecx /* Adjust exponent */ pop ebp /* Return */ ret 8 Add2: sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */ mov ecx, edx sar ebx, 1 /* Shift both mantissae 1 bit right */ sar eax, 1 sar eax, cl /* Shift lMant2 according to exponent difference */ add eax, ebx /* Add the manrissae */ jz AddIs0 mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */ add [ebx + lExp], ecx /* Adjust exponent part 1 */ cdq /* Calculate abs(mantissa) */ xor eax, edx sub eax, edx bsr ecx, eax /* Find most significant bit */ neg ecx /* and calculate needed normalize shift */ add ecx, 30 shl eax, cl dec ecx xor eax, edx /* Go back to original sign */ sub eax, edx mov dword ptr [ebx + lMant], eax /* Safe mantissa and adjust exponent */ sub [ebx + lExp], ecx pop ebx /* Return */ pop ebp ret 8 AddIs0: /* Mantissa is 0, so float to (0,0) */ mov eax, [ebp + PARAM1] pop ebx mov dword ptr [eax + lMant], 0 mov dword ptr [eax + lExp], 0 pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_AddFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); * * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Add */ _FLOATOBJ_AddFloat@8: PUBLIC _FLOATOBJ_AddFloat@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load f into eax */ lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push f on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Add@8 /* Add */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_AddLong(IN OUT PFLOATOBJ pf, IN LONG l); * * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Add */ _FLOATOBJ_AddLong@8: PUBLIC _FLOATOBJ_AddLong@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load l into eax */ lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push l on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Add@8 /* Add */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /******************************************************************************* * VOID * APIENTRY * FLOATOBJ_Sub(IN OUT PFLOATOBJ pf, IN PFLOATOBJ pf1); * */ _FLOATOBJ_Sub@8: PUBLIC _FLOATOBJ_Sub@8 push ebp mov ebp, esp push ebx mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and ebx */ mov ebx, [ebp + PARAM2] mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) and float2 in (ebx,edx) */ mov edx, [ebx + lExp] mov eax, [eax + lMant] mov ebx, [ebx + lMant] cmp ecx, edx /* Check which one has the bigger lExp */ jl Sub2 sub ecx, edx /* Calculate lExp1 - lExp2 */ sar eax, 1 /* Shift both mantissae 1 bit right */ sar ebx, 1 sar ebx, cl /* Shift lMant2 according to exponent difference */ sub eax, ebx /* Substract the manrissae */ jz SubIs0 cdq /* Calculate abs(mantissa) */ xor eax, edx sub eax, edx bsr ecx, eax /* Find most significant bit */ neg ecx /* and calculate needed normalize shift */ add ecx, 30 shl eax, cl dec ecx xor eax, edx /* Go back to original sign */ sub eax, edx mov edx, [ebp + PARAM1] /* Reload pointer to float1 */ pop ebx mov dword ptr [edx + lMant], eax /* Safe mantissa and adjust exponent */ sub [edx + lExp], ecx pop ebp ret 8 Sub2: sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */ mov ecx, edx sar ebx, 1 /* Shift both mantissae 1 bit right */ sar eax, 1 sar eax, cl /* Shift lMant2 according to exponent difference */ sub eax, ebx /* Substract the manrissae */ jz AddIs0 mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */ add [ebx + lExp], ecx /* Adjust exponent part 1 */ cdq /* Calculate abs(mantissa) */ xor eax, edx sub eax, edx bsr ecx, eax /* Find most significant bit */ neg ecx /* and calculate needed normalize shift */ add ecx, 30 shl eax, cl dec ecx xor eax, edx /* Go back to original sign */ sub eax, edx mov dword ptr [ebx + lMant], eax /* Safe mantissa */ sub [ebx + lExp], ecx /* Adjust exponent */ pop ebx /* Return */ pop ebp ret 8 SubIs0: /* Mantissa is 0, so float to (0,0) */ mov eax, [ebp + PARAM1] pop ebx mov dword ptr [eax + lMant], 0 mov dword ptr [eax + lExp], 0 pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_SubFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); * * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Sub */ _FLOATOBJ_SubFloat@8: PUBLIC _FLOATOBJ_SubFloat@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load f into eax */ lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push f on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */ lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Sub@8 /* Substract */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /****************************************************************************** * VOID * APIENTRY * FLOATOBJ_SubLong(IN OUT PFLOATOBJ pf, IN LONG l); * * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Sub */ _FLOATOBJ_SubLong@8: PUBLIC _FLOATOBJ_SubLong@8 push ebp mov ebp, esp sub esp, 8 /* Make room for a FLOATOBJ on the stack */ mov eax, [ebp + PARAM2] /* Load l into eax */ lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */ push eax /* Push l on the stack */ push ecx /* Push pointer to local FLOATOBJ on the stack */ call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */ lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */ push ecx push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */ call _FLOATOBJ_Sub@8 /* Substract */ mov esp, ebp /* Cleanup and return */ pop ebp ret 8 /******************************************************************************* * VOID * APIENTRY * FLOATOBJ_Neg(IN OUT PFLOATOBJ pf); * */ _FLOATOBJ_Neg@4: PUBLIC _FLOATOBJ_Neg@4 push ebp mov ebp, esp mov ecx, [esp + PARAM1] /* Load pf into ecx */ neg dword ptr [ecx + lMant] /* Negate lMant1 */ pop ebp /* Return */ ret 4 END /* EOF */