Update copyright dates with scripts/update-copyrights
[glibc.git] / sysdeps / s390 / strncat-vx.S
blob008905a80653edee1f342d8a086138c52e397617
1 /* Vector optimized 32/64 bit S/390 version of strncat.
2    Copyright (C) 2015-2023 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-strncat.h>
20 #if HAVE_STRNCAT_Z13
22 # include "sysdep.h"
23 # include "asm-syntax.h"
25         .text
27 /* char * strncat (const char *dest, const char *src, size_t n)
28    Concatenate two strings - at most n characters of src.
30    Register usage:
31    -r0=saved dest pointer for return
32    -r1=tmp
33    -r2=dest
34    -r3=src
35    -r4=n
36    -r5=current_len
37    -r6=tmp
38    -r7=tmp
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(STRNCAT_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.  */
54         lgr     %r0,%r2         /* Save destination pointer for return.  */
55         vlvgp   %v31,%r6,%r7    /* Save registers.  */
57         /* STRLEN
58            %r1 = loaded bytes (tmp)
59            %r6 = zero byte index (tmp)
60            %r2 = dst
61         */
62         vlbb    %v16,0(%r2),6   /* Load s until next 4k-byte boundary.  */
63         lcbb    %r1,0(%r2),6    /* Get bytes to 4k-byte boundary or 16.  */
65         vfenezb %v16,%v16,%v16  /* Find element not equal with zero search.  */
66         vlgvb   %r5,%v16,7      /* Load zero index or 16 if not found.  */
67         clrjl   %r5,%r1,.Llen_end /* Found zero within loaded bytes, end.  */
69         /* Align s to 16 byte.  */
70         risbgn  %r1,%r2,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15.  */
71         lghi    %r5,16          /* current_len = 16.  */
72         slr     %r5,%r1         /* Compute bytes to 16bytes boundary.  */
74         /* Find zero in 16byte aligned loop.  */
75 .Llen_loop:
76         vl      %v16,0(%r5,%r2) /* Load s.  */
77         vfenezbs %v16,%v16,%v16 /* Find element not equal with zero search.  */
78         je      .Llen_found     /* Jump away if zero was found.  */
79         vl      %v16,16(%r5,%r2)
80         vfenezbs %v16,%v16,%v16
81         je      .Llen_found16
82         vl      %v16,32(%r5,%r2)
83         vfenezbs %v16,%v16,%v16
84         je      .Llen_found32
85         vl      %v16,48(%r5,%r2)
86         vfenezbs %v16,%v16,%v16
87         je      .Llen_found48
89         aghi    %r5,64
90         j       .Llen_loop      /* No zero -> loop.  */
92 .Llen_found48:
93         aghi    %r5,16
94 .Llen_found32:
95         aghi    %r5,16
96 .Llen_found16:
97         aghi    %r5,16
98 .Llen_found:
99         vlgvb   %r1,%v16,7      /* Load byte index of zero.  */
100         algr    %r5,%r1
102 .Llen_end:
103         /* STRCPY
104            %r1 = zero byte index (tmp)
105            %r6 = loaded bytes (tmp)
106            %r3 = curr src pointer
107            %r2 = curr dst pointer
108            %r7 = border, tmp
109         */
110         la      %r2,0(%r5,%r2)  /* strcpy at end of dst-string.  */
112         vlbb    %v16,0(%r3),6   /* Load s until next 4k-byte boundary.  */
113         lcbb    %r6,0(%r3),6    /* Get bytes to 4k-byte boundary or 16.  */
114         llgfr   %r6,%r6         /* Convert 32bit to 64bit.  */
116         lghi    %r5,0           /* current_len = 0.  */
118         clgrjle %r4,%r6,.Lcpy_remaining_v16 /* If n <= loaded-bytes
119                                                -> process remaining.  */
121         /* n > loaded-byte-count.  */
122         vfenezb %v17,%v16,%v16  /* Find element not equal with zero search.  */
123         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
124         clrjl   %r1,%r6,.Lcpy_found_v16_store /* Found zero within loaded
125                                                  bytes, copy and return.  */
127         /* Align s to 16 byte.  */
128         risbgn  %r7,%r3,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15.  */
129         lghi    %r5,15          /* current_len = 15.  */
130         slr     %r5,%r7         /* Compute highest index to 16byte boundary.  */
132         /* Zero not found and n > loaded-byte-count.  */
133         vstl    %v16,%r5,0(%r2) /* Copy loaded characters - no zero.  */
134         ahi     %r5,1           /* Start loop at next character.  */
136         /*
137           Now we are 16byte aligned, so we can load a full vreg
138           without page fault.
139          */
140         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
141         aghi    %r1,64
142         clgrjl  %r1,%r4,.Lcpy_loop64
144         vl      %v16,0(%r5,%r3) /* Load s.  */
145         clgijl  %r4,17,.Lcpy_remaining_v16 /* If n <=16,
146                                                process remaining bytes.  */
147 .Lcpy_lt64:
148         lgr     %r7,%r4
149         slgfi   %r7,16          /* border_len = n - 16.  */
151         /* If current_len >= border then process remaining bytes.  */
152         clgrjhe %r5,%r7,.Lcpy_remaining_v16
153         vfenezbs %v17,%v16,%v16 /* Find element not equal with zero search.  */
154         je      .Lcpy_found_v16 /* Jump away if zero was found.  */
155         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
156         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
157         aghi    %r5,16
159         clgrjhe %r5,%r7,.Lcpy_remaining_v18
160         vfenezbs %v17,%v18,%v18
161         je      .Lcpy_found_v18
162         vl      %v16,16(%r5,%r3)
163         vst     %v18,0(%r5,%r2)
164         aghi    %r5,16
166         clgrjhe %r5,%r7,.Lcpy_remaining_v16
167         vfenezbs %v17,%v16,%v16
168         je      .Lcpy_found_v16
169         vl      %v18,16(%r5,%r3)
170         vst     %v16,0(%r5,%r2)
171         aghi    %r5,16
173 .Lcpy_remaining_v18:
174         vlr     %v16,%v18
175 .Lcpy_remaining_v16:
176         /* v16 contains the remaining bytes [1...16].
177            Store remaining bytes and append string-termination.  */
178         vfenezb %v17,%v16,%v16  /* Find element not equal with zero search.  */
179         slgrk   %r7,%r4,%r5     /* Remaining bytes = maxlen - current_len.  */
180         aghi    %r7,-1          /* vstl needs highest index.  */
181         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
182         la      %r2,0(%r5,%r2)  /* vstl has no index register.  */
183         /* Zero-index within remaining-bytes, store up to zero and end.  */
184         clgrjle %r1,%r7,.Lcpy_found_v16_store
185         vstl    %v16,%r7,0(%r2) /* Store remaining bytes.  */
186         lghi    %r1,0
187         stc     %r1,1(%r7,%r2)  /* Store string-null-termination beyond n.  */
188 .Lcpy_end:
189         /* Restore saved registers.  */
190         vlgvg   %r6,%v31,0
191         vlgvg   %r7,%v31,1
192         lgr     %r2,%r0         /* Load saved dest-ptr.  */
193         br      %r14
195 .Lcpy_found_v16_32:
196         aghi    %r5,32
197         j       .Lcpy_found_v16
198 .Lcpy_found_v18_48:
199         aghi    %r5,32
200 .Lcpy_found_v18_16:
201         aghi    %r5,16
202 .Lcpy_found_v18:
203         vlr     %v16,%v18
204 .Lcpy_found_v16:
205         /* v16 contains a zero. Store remaining bytes to zero. current_len
206            has not reached border, thus checking for n is not needed!  */
207         vlgvb   %r1,%v17,7      /* Load byte index of zero.  */
208         la      %r2,0(%r5,%r2)
209 .Lcpy_found_v16_store:
210         vstl    %v16,%r1,0(%r2) /* Copy characters including zero.  */
211         j       .Lcpy_end
213         /* Find zero in 16byte aligned loop.  */
214 .Lcpy_loop64:
215         vl      %v16,0(%r5,%r3) /* Load s.  */
216         vfenezbs %v17,%v16,%v16 /* Find element not equal with zero search.  */
217         je      .Lcpy_found_v16 /* Jump away if zero was found.  */
218         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
219         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
220         vfenezbs %v17,%v18,%v18
221         je      .Lcpy_found_v18_16
222         vl      %v16,32(%r5,%r3)
223         vst     %v18,16(%r5,%r2)
224         vfenezbs %v17,%v16,%v16
225         je      .Lcpy_found_v16_32
226         vl      %v18,48(%r5,%r3)
227         vst     %v16,32(%r5,%r2)
228         vfenezbs %v17,%v18,%v18
229         je      .Lcpy_found_v18_48
230         vst     %v18,48(%r5,%r2)
232         aghi    %r5,64
233         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
234         aghi    %r1,64
235         clgrjl  %r1,%r4,.Lcpy_loop64
237         vl      %v16,0(%r5,%r3) /* Load s.  */
238         j       .Lcpy_lt64
239 END(STRNCAT_Z13)
241 # if ! HAVE_STRNCAT_IFUNC
242 strong_alias (STRNCAT_Z13, strncat)
243 # endif
245 # if ! HAVE_STRNCAT_C
246 /* See string/strncat.c and define STRNCAT_PRIMARY.  */
247 strong_alias (STRNCAT_Z13, __strncat)
248 #  if defined SHARED && IS_IN (libc)
249 strong_alias (__strncat, __GI___strncat)
250 #  endif
251 # endif
252 #endif