hurd: fix resolv/tst-resolv-res_init-skeleton.c build
[glibc.git] / sysdeps / s390 / multiarch / wcpncpy-vx.S
blob6a1b587f0ed5a71943deca31efadfd957b7bb090
1 /* Vector optimized 32/64 bit S/390 version of wcpncpy.
2    Copyright (C) 2015-2017 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    <http://www.gnu.org/licenses/>.  */
19 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
21 # include "sysdep.h"
22 # include "asm-syntax.h"
24         .text
26 /* wchar_t * wcpncpy (wchar_t *dest, const wchar_t *src, size_t n)
27    Copies at most n characters of string src to dest
28    returning a pointer to its end or dest+n
29    if src is smaller than n.
31    Register usage:
32    -%r0 = return value
33    -%r1 = zero byte index
34    -%r2 = curr dst pointer
35    -%r3 = curr src pointer
36    -%r4 = n
37    -%r5 = current_len
38    -%r6 = loaded bytes
39    -%r7 = border, tmp
41 ENTRY(__wcpncpy_vx)
42         .machine "z13"
43         .machinemode "zarch_nohighgprs"
45 # if !defined __s390x__
46         llgfr   %r4,%r4
47 # endif /* !defined __s390x__ */
49         clgfi   %r4,0
50         ber     %r14            /* Nothing to do, if n == 0.  */
52         vlbb    %v16,0(%r3),6   /* Load s until next 4k-byte boundary.  */
54         tmll    %r3,3           /* Test if s is 4-byte aligned?  */
55         jne     .Lfallback      /* And use common-code variant if not.  */
57         vlvgp   %v31,%r6,%r7    /* Save registers.  */
58         lghi    %r5,0           /* current_len = 0.  */
60         lcbb    %r6,0(%r3),6    /* Get bytes to 4k-byte boundary or 16.  */
61         llgfr   %r6,%r6         /* Convert 32bit to 64bit.  */
63         /* Check range of maxlen and convert to byte-count.  */
64 # ifdef __s390x__
65         tmhh    %r4,49152       /* Test bit 0 or 1 of maxlen.  */
66         lghi    %r1,-4          /* Max byte-count is 18446744073709551612.  */
67 # else
68         tmlh    %r4,49152       /* Test bit 0 or 1 of maxlen.  */
69         llilf   %r1,4294967292  /* Max byte-count is 4294967292.  */
70 # endif /* !__s390x__ */
71         sllg    %r4,%r4,2       /* Convert character-count to byte-count.  */
72         locgrne %r4,%r1         /* Use max byte-count, if bit 0/1 was one.  */
74         la      %r0,0(%r4,%r2)  /* Save destination pointer + n for return.  */
76         clgrjle %r4,%r6,.Lremaining_v16 /* If n <= loaded-bytes
77                                            -> process remaining.  */
79         /* n > loaded-byte-count */
80         vfenezf %v17,%v16,%v16  /* Find element not equal with zero search.  */
81         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
82         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
83         clrjl   %r1,%r6,.Lfound_v16_store /* Found zero within loaded bytes,
84                                              copy and return.  */
86         /* Align s to 16 byte.  */
87         risbgn  %r7,%r3,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15.  */
88         lghi    %r5,15          /* current_len = 15.  */
89         slr     %r5,%r7         /* Compute highest index to 16byte boundary.  */
91         /* Zero not found and n > loaded-byte-count.  */
92         vstl    %v16,%r5,0(%r2) /* Copy loaded characters - no zero.  */
93         ahi     %r5,1           /* Start loop at next character.  */
95         /* Now we are 16byte aligned, so we can load a full vreg
96            without page fault.  */
97         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
98         aghi    %r1,64
99         clgrjl  %r1,%r4,.Lloop64
101         vl      %v16,0(%r5,%r3) /* Load s.  */
102         clgijl  %r4,17,.Lremaining_v16  /* If n <=16,
103                                            process remaining bytes.  */
104 .Llt64:
105         lgr     %r7,%r4
106         slgfi   %r7,16          /* border_len = n - 16.  */
108         clgrjhe %r5,%r7,.Lremaining_v16 /* If current_len >= border
109                                            then process remaining bytes.  */
110         vfenezfs %v17,%v16,%v16 /* Find element not equal with zero search.  */
111         je      .Lfound_v16     /* Jump away if zero was found.  */
112         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
113         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
114         aghi    %r5,16
116         clgrjhe %r5,%r7,.Lremaining_v18
117         vfenezfs %v17,%v18,%v18
118         je      .Lfound_v18
119         vl      %v16,16(%r5,%r3)
120         vst     %v18,0(%r5,%r2)
121         aghi    %r5,16
123         clgrjhe %r5,%r7,.Lremaining_v16
124         vfenezfs %v17,%v16,%v16
125         je      .Lfound_v16
126         vl      %v18,16(%r5,%r3)
127         vst     %v16,0(%r5,%r2)
128         aghi    %r5,16
130 .Lremaining_v18:
131         vlr     %v16,%v18
132 .Lremaining_v16:
133         /* v16 contains the remaining bytes [1...16].
134            Store remaining bytes and append string-termination.  */
135         vfenezf %v17,%v16,%v16  /* Find element not equal with zero search.  */
136         slgrk   %r7,%r4,%r5     /* Remaining bytes = maxlen - current_len  */
137         aghi    %r7,-1          /* vstl needs highest index.  */
138         la      %r2,0(%r5,%r2)  /* vstl has no index register.  */
139         vlgvb   %r1,%v17,7      /* Load zero index or 16 if not found.  */
140         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
141         /* Zero in remaining bytes? -> jump away (zero-index <= max-index).  */
142         clrjle  %r1,%r7,.Lfound_v16_store
143         vstl    %v16,%r7,0(%r2) /* Store remaining bytes without null
144                                    termination!  */
145 .Lend:
146         /* Restore saved registers.  */
147         vlgvg   %r6,%v31,0
148         vlgvg   %r7,%v31,1
149         lgr     %r2,%r0         /* Load saved dest-ptr.  */
150         br      %r14
152 .Lfound_v16_32:
153         aghi    %r5,32
154         j       .Lfound_v16
155 .Lfound_v18_48:
156         aghi    %r5,32
157 .Lfound_v18_16:
158         aghi    %r5,16
159 .Lfound_v18:
160         vlr     %v16,%v18
161 .Lfound_v16:
162         /* v16 contains a zero. Store remaining bytes to zero. current_len
163            has not reached border, thus checking for n is not needed!  */
164         vlgvb   %r1,%v17,7      /* Load byte index of zero.  */
165         la      %r2,0(%r5,%r2)  /* vstl has no support for index-register.  */
166         aghi    %r1,3           /* Also copy remaining bytes of zero.  */
167 .Lfound_v16_store:
168         vstl    %v16,%r1,0(%r2) /* Copy characters including zero.  */
169         /* Fill remaining bytes with zero - remaining byte count always > 0.  */
170         algr    %r5,%r1         /* Remaining bytes (=%r4) = ...  */
171         slgr    %r4,%r5         /* = n - (currlen + zero_index + 1) */
172         la      %r2,0(%r1,%r2)  /* Pointer to zero. start filling beyond.  */
173         lay     %r0,-3(%r2)     /* Save return-pointer to found zero.  */
174         clgije  %r4,1,.Lend     /* Skip zero-filling, if found-zero is last
175                                    possible character.
176                                    (1 is substracted from r4 below!).  */
177         aghi    %r4,-2          /* mvc with exrl needs count - 1.
178                                    (additional -1, see remaining bytes above) */
179         srlg    %r6,%r4,8       /* Split into 256 byte blocks.  */
180         ltgr    %r6,%r6
181         je      .Lzero_lt256
182 .Lzero_loop256:
183         mvc     1(256,%r2),0(%r2) /* Fill 256 zeros at once.  */
184         la      %r2,256(%r2)
185         brctg   %r6,.Lzero_loop256 /* Loop until all blocks are processed.  */
186 .Lzero_lt256:
187         exrl    %r4,.Lmvc_lt256
188         j       .Lend
189 .Lmvc_lt256:
190         mvc     1(1,%r2),0(%r2)
192         /* Find zero in 16byte aligned loop.  */
193 .Lloop64:
194         vl      %v16,0(%r5,%r3)
195         vfenezfs %v17,%v16,%v16 /* Find element not equal with zero search.  */
196         je      .Lfound_v16     /* Jump away if zero was found.  */
197         vl      %v18,16(%r5,%r3) /* Load next part of s.  */
198         vst     %v16,0(%r5,%r2) /* Store previous part without zero to dst.  */
199         vfenezfs %v17,%v18,%v18
200         je      .Lfound_v18_16
201         vl      %v16,32(%r5,%r3)
202         vst     %v18,16(%r5,%r2)
203         vfenezfs %v17,%v16,%v16
204         je      .Lfound_v16_32
205         vl      %v18,48(%r5,%r3)
206         vst     %v16,32(%r5,%r2)
207         vfenezfs %v17,%v18,%v18
208         je      .Lfound_v18_48
209         vst     %v18,48(%r5,%r2)
211         aghi    %r5,64
212         lgr     %r1,%r5         /* If %r5 + 64 < maxlen? -> loop64.  */
213         aghi    %r1,64
214         clgrjl  %r1,%r4,.Lloop64
216         vl      %v16,0(%r5,%r3) /* Load s.  */
217         j       .Llt64
219 .Lfallback:
220         jg      __wcpncpy_c
221 END(__wcpncpy_vx)
222 #endif /* HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc) */