.
[glibc.git] / sysdeps / sparc / sub_n.S
blob2e217ed67968d86097e3adb4855f93c98a8ffbd1
1 ! sparc __mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
2 ! store difference in a third limb vector.
4 ! Copyright (C) 1995 Free Software Foundation, Inc.
6 ! This file is part of the GNU MP Library.
8 ! The GNU MP Library is free software; you can redistribute it and/or modify
9 ! it under the terms of the GNU Library General Public License as published by
10 ! the Free Software Foundation; either version 2 of the License, or (at your
11 ! option) any later version.
13 ! The GNU MP Library is distributed in the hope that it will be useful, but
14 ! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 ! or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
16 ! License for more details.
18 ! You should have received a copy of the GNU Library General Public License
19 ! along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
20 ! the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 ! INPUT PARAMETERS
24 #define res_ptr %o0
25 #define s1_ptr  %o1
26 #define s2_ptr  %o2
27 #define size    %o3
29 #include "sysdep.h"
31         .text
32         .align  4
33         .global C_SYMBOL_NAME(__mpn_sub_n)
34 C_SYMBOL_NAME(__mpn_sub_n):
35         xor     s2_ptr,res_ptr,%g1
36         andcc   %g1,4,%g0
37         bne     L1                      ! branch if alignment differs
38         nop
39 ! **  V1a  **
40         andcc   res_ptr,4,%g0           ! res_ptr unaligned? Side effect: cy=0
41         beq     L_v1                    ! if no, branch
42         nop
43 /* Add least significant limb separately to align res_ptr and s2_ptr */
44         ld      [s1_ptr],%g4
45         add     s1_ptr,4,s1_ptr
46         ld      [s2_ptr],%g2
47         add     s2_ptr,4,s2_ptr
48         add     size,-1,size
49         subcc   %g4,%g2,%o4
50         st      %o4,[res_ptr]
51         add     res_ptr,4,res_ptr
52 L_v1:   addx    %g0,%g0,%o4             ! save cy in register
53         cmp     size,2                  ! if size < 2 ...
54         bl      Lend2                   ! ... branch to tail code
55         subcc   %g0,%o4,%g0             ! restore cy
57         ld      [s1_ptr+0],%g4
58         addcc   size,-10,size
59         ld      [s1_ptr+4],%g1
60         ldd     [s2_ptr+0],%g2
61         blt     Lfin1
62         subcc   %g0,%o4,%g0             ! restore cy
63 /* Add blocks of 8 limbs until less than 8 limbs remain */
64 Loop1:  subxcc  %g4,%g2,%o4
65         ld      [s1_ptr+8],%g4
66         subxcc  %g1,%g3,%o5
67         ld      [s1_ptr+12],%g1
68         ldd     [s2_ptr+8],%g2
69         std     %o4,[res_ptr+0]
70         subxcc  %g4,%g2,%o4
71         ld      [s1_ptr+16],%g4
72         subxcc  %g1,%g3,%o5
73         ld      [s1_ptr+20],%g1
74         ldd     [s2_ptr+16],%g2
75         std     %o4,[res_ptr+8]
76         subxcc  %g4,%g2,%o4
77         ld      [s1_ptr+24],%g4
78         subxcc  %g1,%g3,%o5
79         ld      [s1_ptr+28],%g1
80         ldd     [s2_ptr+24],%g2
81         std     %o4,[res_ptr+16]
82         subxcc  %g4,%g2,%o4
83         ld      [s1_ptr+32],%g4
84         subxcc  %g1,%g3,%o5
85         ld      [s1_ptr+36],%g1
86         ldd     [s2_ptr+32],%g2
87         std     %o4,[res_ptr+24]
88         addx    %g0,%g0,%o4             ! save cy in register
89         addcc   size,-8,size
90         add     s1_ptr,32,s1_ptr
91         add     s2_ptr,32,s2_ptr
92         add     res_ptr,32,res_ptr
93         bge     Loop1
94         subcc   %g0,%o4,%g0             ! restore cy
96 Lfin1:  addcc   size,8-2,size
97         blt     Lend1
98         subcc   %g0,%o4,%g0             ! restore cy
99 /* Add blocks of 2 limbs until less than 2 limbs remain */
100 Loope1: subxcc  %g4,%g2,%o4
101         ld      [s1_ptr+8],%g4
102         subxcc  %g1,%g3,%o5
103         ld      [s1_ptr+12],%g1
104         ldd     [s2_ptr+8],%g2
105         std     %o4,[res_ptr+0]
106         addx    %g0,%g0,%o4             ! save cy in register
107         addcc   size,-2,size
108         add     s1_ptr,8,s1_ptr
109         add     s2_ptr,8,s2_ptr
110         add     res_ptr,8,res_ptr
111         bge     Loope1
112         subcc   %g0,%o4,%g0             ! restore cy
113 Lend1:  subxcc  %g4,%g2,%o4
114         subxcc  %g1,%g3,%o5
115         std     %o4,[res_ptr+0]
116         addx    %g0,%g0,%o4             ! save cy in register
118         andcc   size,1,%g0
119         be      Lret1
120         subcc   %g0,%o4,%g0             ! restore cy
121 /* Add last limb */
122         ld      [s1_ptr+8],%g4
123         ld      [s2_ptr+8],%g2
124         subxcc  %g4,%g2,%o4
125         st      %o4,[res_ptr+8]
127 Lret1:  retl
128         addx    %g0,%g0,%o0     ! return carry-out from most sign. limb
130 L1:     xor     s1_ptr,res_ptr,%g1
131         andcc   %g1,4,%g0
132         bne     L2
133         nop
134 ! **  V1b  **
135         andcc   res_ptr,4,%g0           ! res_ptr unaligned? Side effect: cy=0
136         beq     L_v1b                   ! if no, branch
137         nop
138 /* Add least significant limb separately to align res_ptr and s2_ptr */
139         ld      [s2_ptr],%g4
140         add     s2_ptr,4,s2_ptr
141         ld      [s1_ptr],%g2
142         add     s1_ptr,4,s1_ptr
143         add     size,-1,size
144         subcc   %g2,%g4,%o4
145         st      %o4,[res_ptr]
146         add     res_ptr,4,res_ptr
147 L_v1b:  addx    %g0,%g0,%o4             ! save cy in register
148         cmp     size,2                  ! if size < 2 ...
149         bl      Lend2                   ! ... branch to tail code
150         subcc   %g0,%o4,%g0             ! restore cy
152         ld      [s2_ptr+0],%g4
153         addcc   size,-10,size
154         ld      [s2_ptr+4],%g1
155         ldd     [s1_ptr+0],%g2
156         blt     Lfin1b
157         subcc   %g0,%o4,%g0             ! restore cy
158 /* Add blocks of 8 limbs until less than 8 limbs remain */
159 Loop1b: subxcc  %g2,%g4,%o4
160         ld      [s2_ptr+8],%g4
161         subxcc  %g3,%g1,%o5
162         ld      [s2_ptr+12],%g1
163         ldd     [s1_ptr+8],%g2
164         std     %o4,[res_ptr+0]
165         subxcc  %g2,%g4,%o4
166         ld      [s2_ptr+16],%g4
167         subxcc  %g3,%g1,%o5
168         ld      [s2_ptr+20],%g1
169         ldd     [s1_ptr+16],%g2
170         std     %o4,[res_ptr+8]
171         subxcc  %g2,%g4,%o4
172         ld      [s2_ptr+24],%g4
173         subxcc  %g3,%g1,%o5
174         ld      [s2_ptr+28],%g1
175         ldd     [s1_ptr+24],%g2
176         std     %o4,[res_ptr+16]
177         subxcc  %g2,%g4,%o4
178         ld      [s2_ptr+32],%g4
179         subxcc  %g3,%g1,%o5
180         ld      [s2_ptr+36],%g1
181         ldd     [s1_ptr+32],%g2
182         std     %o4,[res_ptr+24]
183         addx    %g0,%g0,%o4             ! save cy in register
184         addcc   size,-8,size
185         add     s1_ptr,32,s1_ptr
186         add     s2_ptr,32,s2_ptr
187         add     res_ptr,32,res_ptr
188         bge     Loop1b
189         subcc   %g0,%o4,%g0             ! restore cy
191 Lfin1b: addcc   size,8-2,size
192         blt     Lend1b
193         subcc   %g0,%o4,%g0             ! restore cy
194 /* Add blocks of 2 limbs until less than 2 limbs remain */
195 Loope1b:subxcc  %g2,%g4,%o4
196         ld      [s2_ptr+8],%g4
197         subxcc  %g3,%g1,%o5
198         ld      [s2_ptr+12],%g1
199         ldd     [s1_ptr+8],%g2
200         std     %o4,[res_ptr+0]
201         addx    %g0,%g0,%o4             ! save cy in register
202         addcc   size,-2,size
203         add     s1_ptr,8,s1_ptr
204         add     s2_ptr,8,s2_ptr
205         add     res_ptr,8,res_ptr
206         bge     Loope1b
207         subcc   %g0,%o4,%g0             ! restore cy
208 Lend1b: subxcc  %g2,%g4,%o4
209         subxcc  %g3,%g1,%o5
210         std     %o4,[res_ptr+0]
211         addx    %g0,%g0,%o4             ! save cy in register
213         andcc   size,1,%g0
214         be      Lret1b
215         subcc   %g0,%o4,%g0             ! restore cy
216 /* Add last limb */
217         ld      [s2_ptr+8],%g4
218         ld      [s1_ptr+8],%g2
219         subxcc  %g2,%g4,%o4
220         st      %o4,[res_ptr+8]
222 Lret1b: retl
223         addx    %g0,%g0,%o0     ! return carry-out from most sign. limb
225 ! **  V2  **
226 /* If we come here, the alignment of s1_ptr and res_ptr as well as the
227    alignment of s2_ptr and res_ptr differ.  Since there are only two ways
228    things can be aligned (that we care about) we now know that the alignment
229    of s1_ptr and s2_ptr are the same.  */
231 L2:     cmp     size,1
232         be      Ljone
233         nop
234         andcc   s1_ptr,4,%g0            ! s1_ptr unaligned? Side effect: cy=0
235         beq     L_v2                    ! if no, branch
236         nop
237 /* Add least significant limb separately to align s1_ptr and s2_ptr */
238         ld      [s1_ptr],%g4
239         add     s1_ptr,4,s1_ptr
240         ld      [s2_ptr],%g2
241         add     s2_ptr,4,s2_ptr
242         add     size,-1,size
243         subcc   %g4,%g2,%o4
244         st      %o4,[res_ptr]
245         add     res_ptr,4,res_ptr
247 L_v2:   addx    %g0,%g0,%o4             ! save cy in register
248         addcc   size,-8,size
249         blt     Lfin2
250         subcc   %g0,%o4,%g0             ! restore cy
251 /* Add blocks of 8 limbs until less than 8 limbs remain */
252 Loop2:  ldd     [s1_ptr+0],%g2
253         ldd     [s2_ptr+0],%o4
254         subxcc  %g2,%o4,%g2
255         st      %g2,[res_ptr+0]
256         subxcc  %g3,%o5,%g3
257         st      %g3,[res_ptr+4]
258         ldd     [s1_ptr+8],%g2
259         ldd     [s2_ptr+8],%o4
260         subxcc  %g2,%o4,%g2
261         st      %g2,[res_ptr+8]
262         subxcc  %g3,%o5,%g3
263         st      %g3,[res_ptr+12]
264         ldd     [s1_ptr+16],%g2
265         ldd     [s2_ptr+16],%o4
266         subxcc  %g2,%o4,%g2
267         st      %g2,[res_ptr+16]
268         subxcc  %g3,%o5,%g3
269         st      %g3,[res_ptr+20]
270         ldd     [s1_ptr+24],%g2
271         ldd     [s2_ptr+24],%o4
272         subxcc  %g2,%o4,%g2
273         st      %g2,[res_ptr+24]
274         subxcc  %g3,%o5,%g3
275         st      %g3,[res_ptr+28]
276         addx    %g0,%g0,%o4             ! save cy in register
277         addcc   size,-8,size
278         add     s1_ptr,32,s1_ptr
279         add     s2_ptr,32,s2_ptr
280         add     res_ptr,32,res_ptr
281         bge     Loop2
282         subcc   %g0,%o4,%g0             ! restore cy
284 Lfin2:  addcc   size,8-2,size
285         blt     Lend2
286         subcc   %g0,%o4,%g0             ! restore cy
287 Loope2: ldd     [s1_ptr+0],%g2
288         ldd     [s2_ptr+0],%o4
289         subxcc  %g2,%o4,%g2
290         st      %g2,[res_ptr+0]
291         subxcc  %g3,%o5,%g3
292         st      %g3,[res_ptr+4]
293         addx    %g0,%g0,%o4             ! save cy in register
294         addcc   size,-2,size
295         add     s1_ptr,8,s1_ptr
296         add     s2_ptr,8,s2_ptr
297         add     res_ptr,8,res_ptr
298         bge     Loope2
299         subcc   %g0,%o4,%g0             ! restore cy
300 Lend2:  andcc   size,1,%g0
301         be      Lret2
302         subcc   %g0,%o4,%g0             ! restore cy
303 /* Add last limb */
304 Ljone:  ld      [s1_ptr],%g4
305         ld      [s2_ptr],%g2
306         subxcc  %g4,%g2,%o4
307         st      %o4,[res_ptr]
309 Lret2:  retl
310         addx    %g0,%g0,%o0     ! return carry-out from most sign. limb