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