linux: Add fsmount
[glibc.git] / sysdeps / s390 / wcpncpy-vx.S
bloba2c0f31a3c9fd8375418fb36db8fbb43859950cf
1 /* Vector optimized 32/64 bit S/390 version of wcpncpy.
2    Copyright (C) 2015-2022 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-wcpncpy.h>
20 #if HAVE_WCPNCPY_Z13
22 # include "sysdep.h"
23 # include "asm-syntax.h"
25         .text
27 /* wchar_t * wcpncpy (wchar_t *dest, const wchar_t *src, size_t n)
28    Copies at most n characters of string src to dest
29    returning a pointer to its end or dest+n
30    if src is smaller than n.
32    Register usage:
33    -%r0 = return value
34    -%r1 = zero byte index
35    -%r2 = curr dst pointer
36    -%r3 = curr src pointer
37    -%r4 = n
38    -%r5 = current_len
39    -%r6 = loaded bytes
40    -%r7 = border, tmp
42 ENTRY(WCPNCPY_Z13)
43         .machine "z13"
44         .machinemode "zarch_nohighgprs"
46 # if !defined __s390x__
47         llgfr   %r4,%r4
48 # endif /* !defined __s390x__ */
50         clgfi   %r4,0
51         ber     %r14            /* Nothing to do, if n == 0.  */
53         vlbb    %v16,0(%r3),6   /* Load s until next 4k-byte boundary.  */
55         tmll    %r3,3           /* Test if s is 4-byte aligned?  */
56         jne     .Lfallback      /* And use common-code variant if not.  */
58         vlvgp   %v31,%r6,%r7    /* Save registers.  */
59         lghi    %r5,0           /* current_len = 0.  */
61         lcbb    %r6,0(%r3),6    /* Get bytes to 4k-byte boundary or 16.  */
62         llgfr   %r6,%r6         /* Convert 32bit to 64bit.  */
64         /* Check range of maxlen and convert to byte-count.  */
65 # ifdef __s390x__
66         tmhh    %r4,49152       /* Test bit 0 or 1 of maxlen.  */
67         lghi    %r1,-4          /* Max byte-count is 18446744073709551612.  */
68 # else
69         tmlh    %r4,49152       /* Test bit 0 or 1 of maxlen.  */
70         llilf   %r1,4294967292  /* Max byte-count is 4294967292.  */
71 # endif /* !__s390x__ */
72         sllg    %r4,%r4,2       /* Convert character-count to byte-count.  */
73         locgrne %r4,%r1         /* Use max byte-count, if bit 0/1 was one.  */
75         la      %r0,0(%r4,%r2)  /* Save destination pointer + n for return.  */
77         clgrjle %r4,%r6,.Lremaining_v16 /* If n <= loaded-bytes
78                                            -> process remaining.  */
80         /* n > loaded-byte-count */
81         vfenezf %v17,%v16,%v16  /* Find element not equal with zero search.  */
82         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
83         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
84         clrjl   %r1,%r6,.Lfound_v16_store /* Found zero within loaded bytes,
85                                              copy and return.  */
87         /* Align s to 16 byte.  */
88         risbgn  %r7,%r3,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15.  */
89         lghi    %r5,15          /* current_len = 15.  */
90         slr     %r5,%r7         /* Compute highest index to 16byte boundary.  */
92         /* Zero not found and n > loaded-byte-count.  */
93         vstl    %v16,%r5,0(%r2) /* Copy loaded characters - no zero.  */
94         ahi     %r5,1           /* Start loop at next character.  */
96         /* Now we are 16byte aligned, so we can load a full vreg
97            without page fault.  */
98         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
99         aghi    %r1,64
100         clgrjl  %r1,%r4,.Lloop64
102         vl      %v16,0(%r5,%r3) /* Load s.  */
103         clgijl  %r4,17,.Lremaining_v16  /* If n <=16,
104                                            process remaining bytes.  */
105 .Llt64:
106         lgr     %r7,%r4
107         slgfi   %r7,16          /* border_len = n - 16.  */
109         clgrjhe %r5,%r7,.Lremaining_v16 /* If current_len >= border
110                                            then process remaining bytes.  */
111         vfenezfs %v17,%v16,%v16 /* Find element not equal with zero search.  */
112         je      .Lfound_v16     /* Jump away if zero was found.  */
113         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
114         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
115         aghi    %r5,16
117         clgrjhe %r5,%r7,.Lremaining_v18
118         vfenezfs %v17,%v18,%v18
119         je      .Lfound_v18
120         vl      %v16,16(%r5,%r3)
121         vst     %v18,0(%r5,%r2)
122         aghi    %r5,16
124         clgrjhe %r5,%r7,.Lremaining_v16
125         vfenezfs %v17,%v16,%v16
126         je      .Lfound_v16
127         vl      %v18,16(%r5,%r3)
128         vst     %v16,0(%r5,%r2)
129         aghi    %r5,16
131 .Lremaining_v18:
132         vlr     %v16,%v18
133 .Lremaining_v16:
134         /* v16 contains the remaining bytes [1...16].
135            Store remaining bytes and append string-termination.  */
136         vfenezf %v17,%v16,%v16  /* Find element not equal with zero search.  */
137         slgrk   %r7,%r4,%r5     /* Remaining bytes = maxlen - current_len  */
138         aghi    %r7,-1          /* vstl needs highest index.  */
139         la      %r2,0(%r5,%r2)  /* vstl has no index register.  */
140         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
141         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
142         /* Zero in remaining bytes? -> jump away (zero-index <= max-index).  */
143         clrjle  %r1,%r7,.Lfound_v16_store
144         vstl    %v16,%r7,0(%r2) /* Store remaining bytes without null
145                                    termination!  */
146 .Lend:
147         /* Restore saved registers.  */
148         vlgvg   %r6,%v31,0
149         vlgvg   %r7,%v31,1
150         lgr     %r2,%r0         /* Load saved dest-ptr.  */
151         br      %r14
153 .Lfound_v16_32:
154         aghi    %r5,32
155         j       .Lfound_v16
156 .Lfound_v18_48:
157         aghi    %r5,32
158 .Lfound_v18_16:
159         aghi    %r5,16
160 .Lfound_v18:
161         vlr     %v16,%v18
162 .Lfound_v16:
163         /* v16 contains a zero. Store remaining bytes to zero. current_len
164            has not reached border, thus checking for n is not needed!  */
165         vlgvb   %r1,%v17,7      /* Load byte index of zero.  */
166         la      %r2,0(%r5,%r2)  /* vstl has no support for index-register.  */
167         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
168 .Lfound_v16_store:
169         vstl    %v16,%r1,0(%r2) /* Copy characters including zero.  */
170         /* Fill remaining bytes with zero - remaining byte count always > 0.  */
171         algr    %r5,%r1         /* Remaining bytes (=%r4) = ...  */
172         slgr    %r4,%r5         /* = n - (currlen + zero_index + 1) */
173         la      %r2,0(%r1,%r2)  /* Pointer to zero. start filling beyond.  */
174         lay     %r0,-3(%r2)     /* Save return-pointer to found zero.  */
175         clgije  %r4,1,.Lend     /* Skip zero-filling, if found-zero is last
176                                    possible character.
177                                    (1 is substracted from r4 below!).  */
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)
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      WCPNCPY_C
222 END(WCPNCPY_Z13)
224 # if ! HAVE_WCPNCPY_IFUNC
225 strong_alias (WCPNCPY_Z13, __wcpncpy)
226 weak_alias (__wcpncpy, wcpncpy)
227 # endif
228 #endif