sparc: Use existing macros to avoid code duplication
[glibc.git] / sysdeps / s390 / wcsncpy-vx.S
blobf45fed20a9d7813e4e79c9d250cf1e3d116c47ec
1 /* Vector optimized 32/64 bit S/390 version of wcsncpy.
2    Copyright (C) 2015-2024 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
19 #include <ifunc-wcsncpy.h>
20 #if HAVE_WCSNCPY_Z13
22 # include "sysdep.h"
23 # include "asm-syntax.h"
25         .text
27 /* wchar_t *wcsncpy (const wchar_t *dest, const wchar_t *src, size_t n)
28    Copy at most n characters of string  src to dest.
30    Register usage:
31    -r0=dest pointer for return
32    -r1=tmp, zero byte index
33    -r2=dest
34    -r3=src
35    -r4=n
36    -r5=current_len
37    -r6=tmp, loaded bytes
38    -r7=tmp, border
39    -v16=part of src
40    -v17=index of zero
41    -v18=part of src
42    -v31=register save area for r6, r7
44 ENTRY(WCSNCPY_Z13)
45         .machine "z13"
46         .machinemode "zarch_nohighgprs"
48 # if !defined __s390x__
49         llgfr   %r4,%r4
50 # endif /* !defined __s390x__ */
52         clgfi   %r4,0
53         ber     %r14            /* Nothing to do, if n == 0.  */
55         vlbb    %v16,0(%r3),6   /* Load s until next 4k-byte boundary.  */
57         tmll    %r3,3           /* Test if s is 4-byte aligned?  */
58         jne     .Lfallback      /* And use common-code variant if not.  */
60         vlvgp   %v31,%r6,%r7    /* Save registers.  */
61         lgr     %r0,%r2         /* Save destination pointer for return.  */
63         lcbb    %r6,0(%r3),6    /* Get bytes to 4k-byte boundary or 16.  */
64         llgfr   %r6,%r6         /* Convert 32bit to 64bit.  */
66         lghi    %r5,0           /* current_len = 0.  */
68         /* Check range of maxlen and convert to byte-count.  */
69 # ifdef __s390x__
70         tmhh    %r4,49152       /* Test bit 0 or 1 of n.  */
71         lghi    %r1,-4          /* Max byte-count is 18446744073709551612.  */
72 # else
73         tmlh    %r4,49152       /* Test bit 0 or 1 of n.  */
74         llilf   %r1,4294967292  /* Max byte-count is 4294967292.  */
75 # endif /* !__s390x__ */
76         sllg    %r4,%r4,2       /* Convert character-count to byte-count.  */
77         locgrne %r4,%r1         /* Use max byte-count, if bit 0/1 was one.  */
79         clgrjle %r4,%r6,.Lremaining_v16 /* If n <= loaded-bytes
80                                            -> process remaining.  */
82         /* n > loaded-byte-count.  */
83         vfenezf %v17,%v16,%v16  /* Find element not equal with zero search.  */
84         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
85         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
86         clrjl   %r1,%r6,.Lfound_v16_store /* Found zero within loaded bytes,
87                                              copy and return.  */
89         /* Align s to 16 byte.  */
90         risbgn  %r7,%r3,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15.  */
91         lghi    %r5,15          /* current_len = 15.  */
92         slr     %r5,%r7         /* Compute highest index to 16byte boundary.  */
94         /* Zero not found and n > loaded-byte-count.  */
95         vstl    %v16,%r5,0(%r2) /* Copy loaded characters - no zero.  */
96         ahi     %r5,1           /* Start loop at next character.  */
98         /* Now we are 16byte aligned, so we can load
99            a full vreg without page fault.  */
100         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
101         aghi    %r1,64
102         clgrjl  %r1,%r4,.Lloop64
104         vl      %v16,0(%r5,%r3) /* Load s.  */
105         clgijl  %r4,17,.Lremaining_v16  /* If n <=16, process remaining
106                                            bytes.  */
107 .Llt64:
108         lgr     %r7,%r4
109         slgfi   %r7,16          /* border_len = maxlen - 16.  */
111         clgrjhe %r5,%r7,.Lremaining_v16 /* If current_len >= border
112                                                then process remaining bytes.  */
113         vfenezfs %v17,%v16,%v16 /* Find element not equal with zero search.  */
114         je      .Lfound_v16     /* Jump away if zero was found.  */
115         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
116         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
117         aghi    %r5,16
119         clgrjhe %r5,%r7,.Lremaining_v18
120         vfenezfs %v17,%v18,%v18
121         je      .Lfound_v18
122         vl      %v16,16(%r5,%r3)
123         vst     %v18,0(%r5,%r2)
124         aghi    %r5,16
126         clgrjhe %r5,%r7,.Lremaining_v16
127         vfenezfs %v17,%v16,%v16
128         je      .Lfound_v16
129         vl      %v18,16(%r5,%r3)
130         vst     %v16,0(%r5,%r2)
131         aghi    %r5,16
133 .Lremaining_v18:
134         vlr     %v16,%v18
135 .Lremaining_v16:
136         /* v16 contains the remaining bytes [1...16].
137            Store remaining bytes and append string-termination.  */
138         vfenezf %v17,%v16,%v16  /* Find element not equal with zero search.  */
139         slgrk   %r7,%r4,%r5     /* Remaining bytes = maxlen - current_len.  */
140         aghi    %r7,-1          /* vstl needs highest index.  */
141         la      %r2,0(%r5,%r2)  /* vstl has no index register.  */
142         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
143         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
144         /* Zero in remaining bytes? -> jump away (zero-index < max-index)
145            Do not jump away if zero-index == max-index,
146            but simply copy zero with vstl below.  */
147         clrjl   %r1,%r7,.Lfound_v16_store
148         vstl    %v16,%r7,0(%r2) /* Store remaining bytes without null
149                                    termination!.  */
150 .Lend:
151         /* Restore saved registers.  */
152         vlgvg   %r6,%v31,0
153         vlgvg   %r7,%v31,1
154         lgr     %r2,%r0         /* Load saved dest-ptr.  */
155         br      %r14
157 .Lfound_v16_32:
158         aghi    %r5,32
159         j       .Lfound_v16
160 .Lfound_v18_48:
161         aghi    %r5,32
162 .Lfound_v18_16:
163         aghi    %r5,16
164 .Lfound_v18:
165         vlr     %v16,%v18
166 .Lfound_v16:
167         /* v16 contains a zero. Store remaining bytes to zero. current_len
168            has not reached border, thus checking for n is not needed! */
169         vlgvb   %r1,%v17,7      /* Load byte index of zero.  */
170         la      %r2,0(%r5,%r2)  /* vstl has no support for index-register.  */
171         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
172 .Lfound_v16_store:
173         vstl    %v16,%r1,0(%r2) /* Copy characters including zero.  */
174         /* Fill remaining bytes with zero - remaining count always > 0.  */
175         algr    %r5,%r1         /* Remaining bytes (=%r4) = ...  */
176         slgr    %r4,%r5         /* = maxlen - (currlen + zero_index + 1).  */
177         la      %r2,0(%r1,%r2)  /* Pointer to zero. start filling beyond.  */
178         aghi    %r4,-2          /* mvc with exrl needs count - 1.
179                                    (additional -1, see remaining bytes above) */
180         srlg    %r6,%r4,8       /* Split into 256 byte blocks.  */
181         ltgr    %r6,%r6
182         je      .Lzero_lt256
183 .Lzero_loop256:
184         mvc     1(256,%r2),0(%r2) /* Fill 256 zeros at once.  */
185         la      %r2,256(%r2)
186         brctg   %r6,.Lzero_loop256 /* Loop until all blocks are processed.  */
187 .Lzero_lt256:
188         exrl    %r4,.Lmvc_lt256
189         j       .Lend
190 .Lmvc_lt256:
191         mvc     1(1,%r2),0(%r2)
193         /* Find zero in 16byte aligned loop.  */
194 .Lloop64:
195         vl      %v16,0(%r5,%r3) /* Load s.  */
196         vfenezfs %v17,%v16,%v16 /* Find element not equal with zero search.  */
197         je      .Lfound_v16     /* Jump away if zero was found.  */
198         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
199         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
200         vfenezfs %v17,%v18,%v18
201         je      .Lfound_v18_16
202         vl      %v16,32(%r5,%r3)
203         vst     %v18,16(%r5,%r2)
204         vfenezfs %v17,%v16,%v16
205         je      .Lfound_v16_32
206         vl      %v18,48(%r5,%r3)
207         vst     %v16,32(%r5,%r2)
208         vfenezfs %v17,%v18,%v18
209         je      .Lfound_v18_48
210         vst     %v18,48(%r5,%r2)
212         aghi    %r5,64
213         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
214         aghi    %r1,64
215         clgrjl  %r1,%r4,.Lloop64
217         vl      %v16,0(%r5,%r3) /* Load s.  */
218         j       .Llt64
220 .Lfallback:
221         jg      WCSNCPY_C
222 END(WCSNCPY_Z13)
224 # if ! HAVE_WCSNCPY_IFUNC
225 strong_alias (WCSNCPY_Z13, __wcsncpy)
226 weak_alias (__wcsncpy, wcsncpy)
227 # endif
228 #endif