Annotation of coherent/b/lib/libc/crt/i386/ddiv.s, revision 1.1.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.