1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
| /* SPDX-License-Identifier: GPL-2.0 */
| .file "wm_shrx.S"
| /*---------------------------------------------------------------------------+
| | wm_shrx.S |
| | |
| | 64 bit right shift functions |
| | |
| | Copyright (C) 1992,1995 |
| | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| | |
| | Call from C as: |
| | unsigned FPU_shrx(void *arg1, unsigned arg2) |
| | and |
| | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
| | |
| +---------------------------------------------------------------------------*/
|
| #include "fpu_emu.h"
|
| .text
| /*---------------------------------------------------------------------------+
| | unsigned FPU_shrx(void *arg1, unsigned arg2) |
| | |
| | Extended shift right function. |
| | Fastest for small shifts. |
| | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
| | right by the number of bits specified by the second arg (arg2). |
| | Forms a 96 bit quantity from the 64 bit arg and eax: |
| | [ 64 bit arg ][ eax ] |
| | shift right ---------> |
| | The eax register is initialized to 0 before the shifting. |
| | Results returned in the 64 bit arg and eax. |
| +---------------------------------------------------------------------------*/
|
| ENTRY(FPU_shrx)
| push %ebp
| movl %esp,%ebp
| pushl %esi
| movl PARAM2,%ecx
| movl PARAM1,%esi
| cmpl $32,%ecx /* shrd only works for 0..31 bits */
| jnc L_more_than_31
|
| /* less than 32 bits */
| pushl %ebx
| movl (%esi),%ebx /* lsl */
| movl 4(%esi),%edx /* msl */
| xorl %eax,%eax /* extension */
| shrd %cl,%ebx,%eax
| shrd %cl,%edx,%ebx
| shr %cl,%edx
| movl %ebx,(%esi)
| movl %edx,4(%esi)
| popl %ebx
| popl %esi
| leave
| ret
|
| L_more_than_31:
| cmpl $64,%ecx
| jnc L_more_than_63
|
| subb $32,%cl
| movl (%esi),%eax /* lsl */
| movl 4(%esi),%edx /* msl */
| shrd %cl,%edx,%eax
| shr %cl,%edx
| movl %edx,(%esi)
| movl $0,4(%esi)
| popl %esi
| leave
| ret
|
| L_more_than_63:
| cmpl $96,%ecx
| jnc L_more_than_95
|
| subb $64,%cl
| movl 4(%esi),%eax /* msl */
| shr %cl,%eax
| xorl %edx,%edx
| movl %edx,(%esi)
| movl %edx,4(%esi)
| popl %esi
| leave
| ret
|
| L_more_than_95:
| xorl %eax,%eax
| movl %eax,(%esi)
| movl %eax,4(%esi)
| popl %esi
| leave
| ret
| ENDPROC(FPU_shrx)
|
|
| /*---------------------------------------------------------------------------+
| | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
| | |
| | Extended shift right function (optimized for small floating point |
| | integers). |
| | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
| | right by the number of bits specified by the second arg (arg2). |
| | Forms a 96 bit quantity from the 64 bit arg and eax: |
| | [ 64 bit arg ][ eax ] |
| | shift right ---------> |
| | The eax register is initialized to 0 before the shifting. |
| | The lower 8 bits of eax are lost and replaced by a flag which is |
| | set (to 0x01) if any bit, apart from the first one, is set in the |
| | part which has been shifted out of the arg. |
| | Results returned in the 64 bit arg and eax. |
| +---------------------------------------------------------------------------*/
| ENTRY(FPU_shrxs)
| push %ebp
| movl %esp,%ebp
| pushl %esi
| pushl %ebx
| movl PARAM2,%ecx
| movl PARAM1,%esi
| cmpl $64,%ecx /* shrd only works for 0..31 bits */
| jnc Ls_more_than_63
|
| cmpl $32,%ecx /* shrd only works for 0..31 bits */
| jc Ls_less_than_32
|
| /* We got here without jumps by assuming that the most common requirement
| is for small integers */
| /* Shift by [32..63] bits */
| subb $32,%cl
| movl (%esi),%eax /* lsl */
| movl 4(%esi),%edx /* msl */
| xorl %ebx,%ebx
| shrd %cl,%eax,%ebx
| shrd %cl,%edx,%eax
| shr %cl,%edx
| orl %ebx,%ebx /* test these 32 bits */
| setne %bl
| test $0x7fffffff,%eax /* and 31 bits here */
| setne %bh
| orw %bx,%bx /* Any of the 63 bit set ? */
| setne %al
| movl %edx,(%esi)
| movl $0,4(%esi)
| popl %ebx
| popl %esi
| leave
| ret
|
| /* Shift by [0..31] bits */
| Ls_less_than_32:
| movl (%esi),%ebx /* lsl */
| movl 4(%esi),%edx /* msl */
| xorl %eax,%eax /* extension */
| shrd %cl,%ebx,%eax
| shrd %cl,%edx,%ebx
| shr %cl,%edx
| test $0x7fffffff,%eax /* only need to look at eax here */
| setne %al
| movl %ebx,(%esi)
| movl %edx,4(%esi)
| popl %ebx
| popl %esi
| leave
| ret
|
| /* Shift by [64..95] bits */
| Ls_more_than_63:
| cmpl $96,%ecx
| jnc Ls_more_than_95
|
| subb $64,%cl
| movl (%esi),%ebx /* lsl */
| movl 4(%esi),%eax /* msl */
| xorl %edx,%edx /* extension */
| shrd %cl,%ebx,%edx
| shrd %cl,%eax,%ebx
| shr %cl,%eax
| orl %ebx,%edx
| setne %bl
| test $0x7fffffff,%eax /* only need to look at eax here */
| setne %bh
| orw %bx,%bx
| setne %al
| xorl %edx,%edx
| movl %edx,(%esi) /* set to zero */
| movl %edx,4(%esi) /* set to zero */
| popl %ebx
| popl %esi
| leave
| ret
|
| Ls_more_than_95:
| /* Shift by [96..inf) bits */
| xorl %eax,%eax
| movl (%esi),%ebx
| orl 4(%esi),%ebx
| setne %al
| xorl %ebx,%ebx
| movl %ebx,(%esi)
| movl %ebx,4(%esi)
| popl %ebx
| popl %esi
| leave
| ret
| ENDPROC(FPU_shrxs)
|
|