blob: 1b6c24801d2231bde8d8149db2c08e781086ffcf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001 .file "reg_u_sub.S"
2/*---------------------------------------------------------------------------+
3 | reg_u_sub.S |
4 | |
5 | Core floating point subtraction routine. |
6 | |
7 | Copyright (C) 1992,1993,1995,1997 |
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9 | E-mail billm@suburbia.net |
10 | |
11 | Call from C as: |
12 | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
13 | int control_w) |
14 | Return value is the tag of the answer, or-ed with FPU_Exception if |
15 | one was raised, or -1 on internal error. |
16 | |
17 +---------------------------------------------------------------------------*/
18
19/*
20 | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
21 | Takes two valid reg f.p. numbers (TAG_Valid), which are
22 | treated as unsigned numbers,
23 | and returns their difference as a TAG_Valid or TAG_Zero f.p.
24 | number.
25 | The first number (arg1) must be the larger.
26 | The returned number is normalized.
27 | Basic checks are performed if PARANOID is defined.
28 */
29
30#include "exception.h"
31#include "fpu_emu.h"
32#include "control_w.h"
33
34.text
35ENTRY(FPU_u_sub)
36 pushl %ebp
37 movl %esp,%ebp
38 pushl %esi
39 pushl %edi
40 pushl %ebx
41
42 movl PARAM1,%esi /* source 1 */
43 movl PARAM2,%edi /* source 2 */
44
45 movl PARAM6,%ecx
46 subl PARAM7,%ecx /* exp1 - exp2 */
47
48#ifdef PARANOID
49 /* source 2 is always smaller than source 1 */
50 js L_bugged_1
51
52 testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
53 je L_bugged_2
54
55 testl $0x80000000,SIGH(%esi)
56 je L_bugged_2
57#endif /* PARANOID */
58
59/*--------------------------------------+
60 | Form a register holding the |
61 | smaller number |
62 +--------------------------------------*/
63 movl SIGH(%edi),%eax /* register ms word */
64 movl SIGL(%edi),%ebx /* register ls word */
65
66 movl PARAM3,%edi /* destination */
67 movl PARAM6,%edx
68 movw %dx,EXP(%edi) /* Copy exponent to destination */
69
70 xorl %edx,%edx /* register extension */
71
72/*--------------------------------------+
73 | Shift the temporary register |
74 | right the required number of |
75 | places. |
76 +--------------------------------------*/
77
78 cmpw $32,%cx /* shrd only works for 0..31 bits */
79 jnc L_more_than_31
80
81/* less than 32 bits */
82 shrd %cl,%ebx,%edx
83 shrd %cl,%eax,%ebx
84 shr %cl,%eax
85 jmp L_shift_done
86
87L_more_than_31:
88 cmpw $64,%cx
89 jnc L_more_than_63
90
91 subb $32,%cl
92 jz L_exactly_32
93
94 shrd %cl,%eax,%edx
95 shr %cl,%eax
96 orl %ebx,%ebx
97 jz L_more_31_no_low /* none of the lowest bits is set */
98
99 orl $1,%edx /* record the fact in the extension */
100
101L_more_31_no_low:
102 movl %eax,%ebx
103 xorl %eax,%eax
104 jmp L_shift_done
105
106L_exactly_32:
107 movl %ebx,%edx
108 movl %eax,%ebx
109 xorl %eax,%eax
110 jmp L_shift_done
111
112L_more_than_63:
113 cmpw $65,%cx
114 jnc L_more_than_64
115
116 /* Shift right by 64 bits */
117 movl %eax,%edx
118 orl %ebx,%ebx
119 jz L_more_63_no_low
120
121 orl $1,%edx
122 jmp L_more_63_no_low
123
124L_more_than_64:
125 jne L_more_than_65
126
127 /* Shift right by 65 bits */
128 /* Carry is clear if we get here */
129 movl %eax,%edx
130 rcrl %edx
131 jnc L_shift_65_nc
132
133 orl $1,%edx
134 jmp L_more_63_no_low
135
136L_shift_65_nc:
137 orl %ebx,%ebx
138 jz L_more_63_no_low
139
140 orl $1,%edx
141 jmp L_more_63_no_low
142
143L_more_than_65:
144 movl $1,%edx /* The shifted nr always at least one '1' */
145
146L_more_63_no_low:
147 xorl %ebx,%ebx
148 xorl %eax,%eax
149
150L_shift_done:
151L_subtr:
152/*------------------------------+
153 | Do the subtraction |
154 +------------------------------*/
155 xorl %ecx,%ecx
156 subl %edx,%ecx
157 movl %ecx,%edx
158 movl SIGL(%esi),%ecx
159 sbbl %ebx,%ecx
160 movl %ecx,%ebx
161 movl SIGH(%esi),%ecx
162 sbbl %eax,%ecx
163 movl %ecx,%eax
164
165#ifdef PARANOID
166 /* We can never get a borrow */
167 jc L_bugged
168#endif /* PARANOID */
169
170/*--------------------------------------+
171 | Normalize the result |
172 +--------------------------------------*/
173 testl $0x80000000,%eax
174 jnz L_round /* no shifting needed */
175
176 orl %eax,%eax
177 jnz L_shift_1 /* shift left 1 - 31 bits */
178
179 orl %ebx,%ebx
180 jnz L_shift_32 /* shift left 32 - 63 bits */
181
182/*
183 * A rare case, the only one which is non-zero if we got here
184 * is: 1000000 .... 0000
185 * -0111111 .... 1111 1
186 * --------------------
187 * 0000000 .... 0000 1
188 */
189
190 cmpl $0x80000000,%edx
191 jnz L_must_be_zero
192
193 /* Shift left 64 bits */
194 subw $64,EXP(%edi)
195 xchg %edx,%eax
196 jmp fpu_reg_round
197
198L_must_be_zero:
199#ifdef PARANOID
200 orl %edx,%edx
201 jnz L_bugged_3
202#endif /* PARANOID */
203
204 /* The result is zero */
205 movw $0,EXP(%edi) /* exponent */
206 movl $0,SIGL(%edi)
207 movl $0,SIGH(%edi)
208 movl TAG_Zero,%eax
209 jmp L_exit
210
211L_shift_32:
212 movl %ebx,%eax
213 movl %edx,%ebx
214 movl $0,%edx
215 subw $32,EXP(%edi) /* Can get underflow here */
216
217/* We need to shift left by 1 - 31 bits */
218L_shift_1:
219 bsrl %eax,%ecx /* get the required shift in %ecx */
220 subl $31,%ecx
221 negl %ecx
222 shld %cl,%ebx,%eax
223 shld %cl,%edx,%ebx
224 shl %cl,%edx
225 subw %cx,EXP(%edi) /* Can get underflow here */
226
227L_round:
228 jmp fpu_reg_round /* Round the result */
229
230
231#ifdef PARANOID
232L_bugged_1:
233 pushl EX_INTERNAL|0x206
234 call EXCEPTION
235 pop %ebx
236 jmp L_error_exit
237
238L_bugged_2:
239 pushl EX_INTERNAL|0x209
240 call EXCEPTION
241 pop %ebx
242 jmp L_error_exit
243
244L_bugged_3:
245 pushl EX_INTERNAL|0x210
246 call EXCEPTION
247 pop %ebx
248 jmp L_error_exit
249
250L_bugged_4:
251 pushl EX_INTERNAL|0x211
252 call EXCEPTION
253 pop %ebx
254 jmp L_error_exit
255
256L_bugged:
257 pushl EX_INTERNAL|0x212
258 call EXCEPTION
259 pop %ebx
260 jmp L_error_exit
261
262L_error_exit:
263 movl $-1,%eax
264
265#endif /* PARANOID */
266
267L_exit:
268 popl %ebx
269 popl %edi
270 popl %esi
271 leave
272 ret