|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.