Annotation of coherent/b/lib/libc/crt/i386/ddiv.s, revision 1.1

1.1     ! root        1: //////////
        !             2: / libc/crt/i386/ddiv.s
        !             3: / i386 C runtime library.
        !             4: / IEEE software floating point support.
        !             5: //////////
        !             6: 
        !             7: //////////
        !             8: / double _ddiv(double d)
        !             9: / Return d / %edx:eax in %edx:%eax.
        !            10: /
        !            11: / double _drdiv(double d)
        !            12: / Return %edx:eax / d in %edx:%eax.
        !            13: /
        !            14: / The hard part of floating point division is computing the result mantissa,
        !            15: / i.e. the quotient of the numerator mantissa by the denominator mantissa;
        !            16: / all are 53-bit quantities.
        !            17: / We shift the denominator mantissa to make it as large as possible,
        !            18: / then use i386 "divl" (64-bit by 32-bit unsigned integer divide)
        !            19: / twice to find the two quotient dwords efficiently.
        !            20: /
        !            21: / This does not handle denormals, though it could without much trouble.
        !            22: //////////
        !            23: 
        !            24: d      .equ    8
        !            25: BIAS   .equ    1023
        !            26: EXPMASK        .equ    0x7FF00000
        !            27: MANMASK        .equ    0x000FFFFF
        !            28: SGNMASK        .equ    0x80000000
        !            29: HIDDEN .equ    0x00100000
        !            30: 
        !            31:        .globl  _ddiv
        !            32:        .globl  _drdiv
        !            33: 
        !            34: _ddiv:
        !            35:        xchgl   %edx, 8(%esp)
        !            36:        xchgl   %eax, 4(%esp)           / exchange arg order
        !            37: /      jmp     _drdiv                  / and fall through to divide
        !            38: 
        !            39: / Numerator is in EDX:EAX, call it A = hiA:loA.
        !            40: / Denominator is on stack, call it B = hiB:loB.
        !            41: / Compute the quotient A/B, call it Q = hiQ:loQ.
        !            42: _drdiv:
        !            43:        push    %ebp
        !            44:        movl    %ebp, %esp
        !            45:        push    %esi
        !            46:        push    %edi
        !            47:        push    %ebx
        !            48:        push    %ecx
        !            49: 
        !            50:        movl    %esi, d+4(%ebp)
        !            51:        movl    %edi, d(%ebp)           / B to ESI:EDI
        !            52:                                        / now done with EBP as index register
        !            53: 
        !            54:        / Compute result sign.
        !            55:        movl    %ebx, %edx
        !            56:        xorl    %ebx, %esi
        !            57:        andl    %ebx, $SGNMASK
        !            58:        push    %ebx                    / save result sign bit
        !            59: 
        !            60:        / Check for special cases +-0.0, +-infinity, NaN on each side.
        !            61:        movl    %ecx, %esi
        !            62:        andl    %ecx, $EXPMASK
        !            63:        movl    %ebx, %edx
        !            64:        andl    %ebx, $EXPMASK
        !            65:        jz      ?lhszero                / A is 0.0; ignore denormal
        !            66:        cmpl    %ebx, $EXPMASK
        !            67:        jz      ?lhsmax                 / A is +-infinity or NaN
        !            68:        orl     %ecx, %ecx
        !            69:        jz      ?inf                    / normal/0.0, return +-infinity; ignore denormal
        !            70:        cmpl    %ecx, $EXPMASK
        !            71:        jz      ?rhsmax                 / normal/+-infinity or normal/NaN
        !            72: 
        !            73:        / Compute probable result exponent in EBX.
        !            74:        / It might get incremented below (so 0 might become 1).
        !            75:        shrl    %ebx, $20               / A biased exp in EBX
        !            76:        shrl    %ecx, $20               / B biased exp in ECX
        !            77:        subl    %ecx, $BIAS-1           / unbiased, fudged to get right result
        !            78:        subl    %ebx, %ecx              / form biased result exponent
        !            79:        jl      ?zero                   / underflow, return 0.0
        !            80:        cmpl    %ebx, $EXPMASK>>20
        !            81:        jge     ?inf                    / overflow, return +-infinity
        !            82: 
        !            83:        / Extract the mantissas.
        !            84:        / Shift the denominator mantissa to range 2^63 <= B < 2^64.
        !            85:        andl    %edx, $MANMASK
        !            86:        orl     %edx, $HIDDEN           / extract A mantissa, restore hidden bit
        !            87:        andl    %esi, $MANMASK
        !            88:        orl     %esi, $HIDDEN           / extract B mantissa, restore hidden bit
        !            89:        shld    %esi, %edi, $11
        !            90:        shll    %edi, $11               / shift left, B bit 31 is now 1
        !            91:        jnz     ?hard                   / loB is nonzero
        !            92: 
        !            93:        / Division is easy when the lo divisor dword is zero:
        !            94:        / perform a 96-bit by 32-bit divide of hiA:loA:0 by hiB to get
        !            95:        / a 64-bit quotient and a 32-bit remainder,
        !            96:        / then zero-extend the remainder to 64 bits.
        !            97:        / hiQ = q1 = A/hiB and r1 = A%hiB, then loQ = q2 = r1:0/hiB.
        !            98:        / This is a special case for efficiency; division by any double with
        !            99:        / up to 32 mantissa bits, notably any int or unsigned, is quite fast.
        !           100:        divl    %esi                    / q1 = A/hiB to EAX, r1 = A%hiB to EDX
        !           101:        movl    %ebp, %eax              / save q1
        !           102:        subl    %eax, %eax              / r1:0 in EDX:EAX
        !           103:        divl    %esi                    / q2 = r1:0/hiB to EAX, r to EDX
        !           104:        xchgl   %ebp, %edx              / result quotient in EDX:EAX
        !           105:        subl    %ecx, %ecx              / r:0 in EBP:ECX
        !           106: 
        !           107:        / The quotient is in EDX:EAX, the remainder is in EBP:ECX.
        !           108:        / Round up the quotient when remainder >= B / 2, i.e. 2*r >= B.
        !           109: ?remtest:
        !           110:        shld    %ebp, %ecx, $1          / 2*hiR
        !           111:        jc      ?roundup                / too big
        !           112:        cmpl    %ebp, %esi
        !           113:        jb      ?position               / 2*r < B
        !           114:        ja      ?roundup                / 2*r > B, round up
        !           115:        shll    %ecx, $1                / 2*loR
        !           116:        cmpl    %ecx, %edi              / hi(2*R) == hiB, compare lo dword
        !           117:        jb      ?position               / 2*r < B
        !           118: 
        !           119:        / Round up the quotient in EDX:EAX.
        !           120: ?roundup:
        !           121:        addl    %eax, $1
        !           122:        adcl    %edx, $0
        !           123: 
        !           124:        / The quotient in EDX:EAX might be correctly positioned as it stands,
        !           125:        / or it might require a 1-bit right shift.
        !           126: ?position:
        !           127:        testl   %edx, $HIDDEN<<1        / check if shift required
        !           128:        jz      ?pack                   / no shift required
        !           129: ?rshift:
        !           130:        incl    %ebx                    / bump exponent
        !           131:        shrd    %eax, %edx, $1
        !           132:        pushfl                          / save CF for rounding
        !           133:        shrl    %edx, $1                / shift EDX:EAX right by 1 bit
        !           134:        popfl                           / restore CF
        !           135:        adcl    %eax, $0
        !           136:        adcl    %edx, $0                / round if appropriate
        !           137:        testl   %edx, $HIDDEN<<1        / watch out for carry past hidden bit
        !           138:        jnz     ?rshift
        !           139: 
        !           140:        / Pack result mantissa in EDX:EAX with exponent from EBX and sign from stack.
        !           141: ?pack:
        !           142:        orl     %ebx, %ebx
        !           143:        jle     ?zero                   / exponent underflow, return 0.0
        !           144:        cmp     %ebx, $EXPMASK>>20
        !           145:        jge     ?inf                    / exponent overflow, return infinity
        !           146:        shll    %ebx, $20               / position exponent
        !           147:        andl    %edx, $MANMASK          / mask off hidden bit
        !           148:        orl     %edx, %ebx              / pack mantissa and exponent
        !           149:        pop     %ecx
        !           150:        orl     %edx, %ecx              / pack with sign
        !           151: 
        !           152: ?done:
        !           153:        pop     %ecx
        !           154:        pop     %ebx
        !           155:        pop     %edi
        !           156:        pop     %esi
        !           157:        pop     %ebp
        !           158:        ret
        !           159: 
        !           160: / Numerator is 0.0 (or denormal, ignored here).
        !           161: ?lhszero:
        !           162:        jecxz   ?NaN                    / 0/0, return NaN; ignore denormal
        !           163:        cmpl    %ecx, $EXPMASK
        !           164:        jnz     ?zero                   / 0/normal, return 0.0
        !           165: ?rhsmax:
        !           166:        / Numerator is normal or 0, denominator is +-infinity or NaN.
        !           167:        andl    %esi, $MANMASK
        !           168:        jnz     ?NaN                    / A/NaN, return NaN
        !           169:        orl     %edi, %edi
        !           170:        jnz     ?NaN                    / A/NaN, return NaN
        !           171: /      jmp     ?zero                   / 0/+-infinity or normal/+-infinity, return 0.0 
        !           172:                                        / fall through...
        !           173: / Return +0.0.
        !           174: ?zero:
        !           175:        pop     %edx                    / pop sign bit and ignore
        !           176:        subl    %edx, %edx              / return 0.0
        !           177: ?zeroeax:
        !           178:        subl    %eax, %eax
        !           179:        jmp     ?done
        !           180: 
        !           181: / Numerator is +-infinity or NaN.
        !           182: ?lhsmax:
        !           183:        andl    %edx, $MANMASK
        !           184:        jnz     ?NaN                    / NaN/B, return NaN
        !           185:        orl     %eax, %eax
        !           186:        jnz     ?NaN                    / NaN/B, return NaN
        !           187:        cmpl    %ecx, $EXPMASK
        !           188:        jz      ?NaN                    / +-infinity/NaN or +-infinity/+-infinity
        !           189: /      jmp     ?inf                    / +-infinity/normal or +-infinity/0, return infinity
        !           190:                                        / fall through...
        !           191:                
        !           192: / Return +-infinity.
        !           193: ?inf:
        !           194:        pop     %edx                    / pop result sign bit
        !           195:        orl     %edx, $EXPMASK          / max exp, zero mantissa for infinity
        !           196:        jmp     ?zeroeax
        !           197: 
        !           198: / Return NaN.
        !           199: ?NaN:
        !           200:        pop     %edx                    / pop sign bit and ignore
        !           201:        movl    %edx, $EXPMASK|MANMASK  / max exp, nonzero mantissa for NaN
        !           202:        jmp     ?zeroeax
        !           203: 
        !           204: / The hard case performs a 128-bit by 64-bit division of hiA:loA:0:0
        !           205: / by hiB:loB to get a 64-bit quotient hiQ:loQ and a 64-bit remainder hiR:loR.
        !           206: / Execute the following code twice to compute the two quotient dwords,
        !           207: / saving hiQ in EBP and using it as a termination flag.
        !           208: / Each iteration does a 96-bit by 64-bit divide to get a 32-bit quotient
        !           209: / and a 64-bit remainder.
        !           210: / Use q = A / hiB as a guess at the quotient,
        !           211: / then decrement the remainder r = A % hiB by loB*q.
        !           212: / We may need to decrement q once or twice to get the right quotient.
        !           213: 
        !           214: ?hard:
        !           215:        push    %ebx                    / save result exponent
        !           216:        subl    %ebp, %ebp              / clear flag for first pass
        !           217: ?divide:
        !           218:        divl    %esi                    / q = A/hiB to EAX, r = A%hiB to EDX
        !           219:        movl    %ecx, %eax              / save q in ECX
        !           220:        movl    %ebx, %edx              / and save r in EBX
        !           221:        mull    %edi                    / loB*q to EDX:EAX
        !           222:        xchgl   %edx, %ebx              / r to EDX, hi(loB*q) to EBX
        !           223:        negl    %eax                    / 0-lo(loB*q) to EAX
        !           224:        sbbl    %edx, %ebx              / EDX:EAX gets r-loB*q
        !           225:        jnc     ?gotcha                 / q is the right quotient
        !           226: 
        !           227:        / q is too big a guess, adjust to q' = q-1 and adjust the remainder.
        !           228:        / This gets executed at most twice (because the high bit of B is 1).
        !           229: ?adjust:
        !           230:        decl    %ecx                    / decrement the quotient
        !           231:        addl    %eax, %edi
        !           232:        adcl    %edx, %esi              / add B back to remainder
        !           233:        jnc     ?adjust                 / repeat if still negative
        !           234: 
        !           235:        / The correct dword q is in ECX, the remainder r is in EDX:EAX.
        !           236: ?gotcha:
        !           237:        orl     %ebp, %ebp
        !           238:        jz      ?loQ                    / repeat to find loQ
        !           239:        xchgl   %ebp, %edx
        !           240:        xchgl   %ecx, %eax              / q to EDX:EAX, r to EBP:ECX
        !           241:        pop     %ebx                    / restore result exponent
        !           242:        jmp     ?remtest
        !           243: 
        !           244:        / Compute the lo dword of the quotient.
        !           245:        / r is in EDX:EAX, hiQ is in ECX.
        !           246: ?loQ:
        !           247:        movl    %ebp, %ecx              / save hiQ (nonzero) in EBP
        !           248:        cmpl    %edx, %esi              / be wary of overflow on divide
        !           249:        jb      ?divide                 / no overflow, proceed as above
        !           250: 
        !           251:        / Since r is the remainder of the first division by B,
        !           252:        / it must be strictly less than B.  But it is possible that hiR = hiB,
        !           253:        / in which case the divide using "divl" would overflow.
        !           254:        / For this case, use q2 = 0xFFFFFFFF = 2^32 - 1 as the quotient guess.
        !           255:        / Compute the adjusted remainder r2 = r - q2*B as r - 2^32 * B + B.
        !           256:        movl    %ecx, $0xFFFFFFFF       / q2
        !           257:        subl    %eax, %edi              / loR - loB, must be negative
        !           258: /      sbbl    %edx, %esi              / hiR = hiB, so hi dword EDX becomes 0
        !           259:        movl    %edx, %eax              / EDX:EAX *= 2^32; EDX is now negative
        !           260:        movl    %eax, %edi              / 0 + loB
        !           261:        addl    %edx, %esi              / add back B to EDX:EAX
        !           262:        jc      ?gotcha                 / remainder became positive, q2 is ok
        !           263:        jmp     ?adjust                 / remainder stayed negative, adjust q2
        !           264: 
        !           265: / end of libc/crt/i386/ddiv.s

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.