Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/math-emu/reg_u_add.S
26424 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
.file "reg_u_add.S"
3
/*---------------------------------------------------------------------------+
4
| reg_u_add.S |
5
| |
6
| Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the |
7
| result in a destination FPU_REG. |
8
| |
9
| Copyright (C) 1992,1993,1995,1997 |
10
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
11
| E-mail [email protected] |
12
| |
13
| Call from C as: |
14
| int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
15
| int control_w) |
16
| Return value is the tag of the answer, or-ed with FPU_Exception if |
17
| one was raised, or -1 on internal error. |
18
| |
19
+---------------------------------------------------------------------------*/
20
21
/*
22
| Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
23
| Takes two valid reg f.p. numbers (TAG_Valid), which are
24
| treated as unsigned numbers,
25
| and returns their sum as a TAG_Valid or TAG_Special f.p. number.
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
35
SYM_FUNC_START(FPU_u_add)
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
movl %ecx,%edx
47
subl PARAM7,%ecx /* exp1 - exp2 */
48
jge L_arg1_larger
49
50
/* num1 is smaller */
51
movl SIGL(%esi),%ebx
52
movl SIGH(%esi),%eax
53
54
movl %edi,%esi
55
movl PARAM7,%edx
56
negw %cx
57
jmp L_accum_loaded
58
59
L_arg1_larger:
60
/* num1 has larger or equal exponent */
61
movl SIGL(%edi),%ebx
62
movl SIGH(%edi),%eax
63
64
L_accum_loaded:
65
movl PARAM3,%edi /* destination */
66
movw %dx,EXP(%edi) /* Copy exponent to destination */
67
68
xorl %edx,%edx /* clear the extension */
69
70
#ifdef PARANOID
71
testl $0x80000000,%eax
72
je L_bugged
73
74
testl $0x80000000,SIGH(%esi)
75
je L_bugged
76
#endif /* PARANOID */
77
78
/* The number to be shifted is in %eax:%ebx:%edx */
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
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
124
L_more_than_64:
125
movl $1,%edx /* The shifted nr always at least one '1' */
126
127
L_more_63_no_low:
128
xorl %ebx,%ebx
129
xorl %eax,%eax
130
131
L_shift_done:
132
/* Now do the addition */
133
addl SIGL(%esi),%ebx
134
adcl SIGH(%esi),%eax
135
jnc L_round_the_result
136
137
/* Overflow, adjust the result */
138
rcrl $1,%eax
139
rcrl $1,%ebx
140
rcrl $1,%edx
141
jnc L_no_bit_lost
142
143
orl $1,%edx
144
145
L_no_bit_lost:
146
incw EXP(%edi)
147
148
L_round_the_result:
149
jmp fpu_reg_round /* Round the result */
150
151
152
153
#ifdef PARANOID
154
/* If we ever get here then we have problems! */
155
L_bugged:
156
pushl EX_INTERNAL|0x201
157
call EXCEPTION
158
pop %ebx
159
movl $-1,%eax
160
jmp L_exit
161
162
L_exit:
163
popl %ebx
164
popl %edi
165
popl %esi
166
leave
167
RET
168
#endif /* PARANOID */
169
SYM_FUNC_END(FPU_u_add)
170
171