hc
2023-10-25 6c2073b7aa40e29d0eca7d571dd7bc590c7ecaa7
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)