sparc: Use existing macros to avoid code duplication
[glibc.git] / sysdeps / s390 / wcsspn-vx.S
blob84366abfb0e0a5054ec455fbce4039d68535a46d
1 /* Vector optimized 32/64 bit S/390 version of wcsspn.
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-wcsspn.h>
20 #if HAVE_WCSSPN_Z13
22 # include "sysdep.h"
23 # include "asm-syntax.h"
25         .text
27 /* size_t wcsspn (const wchar_t *s, const wchar_t * accept)
28    The wcsspn() function calculates the length of the initial segment
29    of s which consists entirely of characters in accept.
31    This method checks the length of accept string. If it fits entirely
32    in one vector register, a fast algorithm is used, which does not need
33    to check multiple parts of accept-string. Otherwise a slower full
34    check of accept-string is used.
36    register overview:
37    r3:  pointer to start of accept-string
38    r2:  pointer to start of search-string
39    r4:  loaded byte count of vl search-string
40    r0:  found byte index
41    r1:  current return len of s
42    v16: search-string
43    v17: accept-string
44    v18: temp-vreg
46    ONLY FOR SLOW:
47    v19: first accept-string
48    v20: zero for preparing acc-vector
49    v21: global mask; 1 indicates a match between
50         search-string-vreg and any accept-character
51    v22: current mask; 1 indicates a match between
52         search-string-vreg and any accept-character in current acc-vreg
53    v30, v31: for re-/storing registers r6, r8, r9
54    r5:  current len of accept-string
55    r6:  zero-index in search-string or 16 if no zero
56         or min(zero-index, loaded byte count)
57    r8:  >0, if former accept-string-part contains a zero,
58         otherwise =0;
59    r9: loaded byte count of vlbb accept-string
61 ENTRY(WCSSPN_Z13)
62         .machine "z13"
63         .machinemode "zarch_nohighgprs"
65         tmll    %r2,3           /* Test if s is 4-byte aligned?  */
66         jne     .Lfallback      /* And use common-code variant if not.  */
68         /*
69           Check if accept-string fits in one vreg:
70           ----------------------------------------
71         */
72         vlbb    %v17,0(%r3),6   /* Load accept.  */
73         lcbb    %r4,0(%r3),6
74         jo      .Lcheck_onbb    /* Special case if accept lays
75                                    on block-boundary.  */
76 .Lcheck_notonbb:
77         vistrfs %v17,%v17       /* Fill with zeros after first zero.  */
78         je      .Lfast          /* Zero found -> accept fits in one vreg.  */
79         j       .Lslow          /* No zero -> accept exceeds one vreg.  */
81 .Lcheck_onbb:
82         /* Accept lays on block-boundary.  */
83         nill    %r4,65532       /* Recognize only fully loaded characters.  */
84         je      .Lcheck_onbb2   /* Reload vr if no full wchar_t.  */
85         vfenezf %v18,%v17,%v17  /* Search zero in loaded accept bytes.  */
86         vlgvb   %r0,%v18,7      /* Get index of zero or 16 if not found.  */
87         clrjl   %r0,%r4,.Lcheck_notonbb /* Zero index < loaded bytes count ->
88                                             Accept fits in one vreg;
89                                             Fill with zeros and proceed
90                                             with FAST.  */
91 .Lcheck_onbb2:
92         vl      %v17,0(%r3)     /* Load accept, which exceeds loaded bytes.  */
93         j       .Lcheck_notonbb /* Check if accept fits in one vreg.  */
96         /*
97           Search s for accept in one vreg
98           -------------------------------
99         */
100 .Lfast:
101         /* Complete accept-string in v17 and remaining bytes are zero.  */
103         vlbb    %v16,0(%r2),6   /* Load s until next 4k-byte boundary.  */
104         lcbb    %r1,0(%r2),6    /* Get bytes to 4k-byte boundary or 16.  */
106         vfaezfs %v16,%v16,%v17,8 /* Find first element in v16
107                                     unequal to any in v17
108                                     or first zero element.  */
110         vlgvb   %r0,%v16,7      /* Load byte index of found element.  */
111         /* If found index is within loaded bytes (%r0 < %r1),
112            return with found element index (=equal count).  */
113         clr     %r0,%r1
114         srlg    %r0,%r0,2       /* Convert byte-count to character-count.  */
115         locgrl  %r2,%r0
116         blr     %r14
118         /* Align s to 16 byte.  */
119         risbgn  %r4,%r2,60,128+63,0 /* %r3 = bits 60-63 of %r2 'and' 15.  */
120         lghi    %r1,16          /* current_len = 16.  */
121         slr     %r1,%r4         /* Compute bytes to 16bytes boundary.  */
123 .Lfast_loop:
124         vl      %v16,0(%r1,%r2) /* Load search-string.  */
125         vfaezfs %v16,%v16,%v17,8 /* Find first element in v16
126                                     unequal to any in v17
127                                     or first zero element.  */
128         jno     .Lfast_loop_found
129         vl      %v16,16(%r1,%r2)
130         vfaezfs %v16,%v16,%v17,8
131         jno     .Lfast_loop_found16
132         vl      %v16,32(%r1,%r2)
133         vfaezfs %v16,%v16,%v17,8
134         jno     .Lfast_loop_found32
135         vl      %v16,48(%r1,%r2)
136         vfaezfs %v16,%v16,%v17,8
137         jno     .Lfast_loop_found48
139         aghi    %r1,64
140         j       .Lfast_loop     /* Loop if no element was unequal to accept
141                                    and not zero.  */
143         /* Found unequal or zero element.  */
144 .Lfast_loop_found48:
145         aghi    %r1,16
146 .Lfast_loop_found32:
147         aghi    %r1,16
148 .Lfast_loop_found16:
149         aghi    %r1,16
150 .Lfast_loop_found:
151         vlgvb   %r0,%v16,7      /* Load byte index of found element.  */
152         algrk   %r2,%r1,%r0     /* And add it to current len.  */
153         srlg    %r2,%r2,2       /* Convert byte-count to character-count.  */
154         br      %r14
157         /*
158           Search s for accept in multiple vregs
159           -------------------------------------
160         */
161 .Lslow:
162         /* Save registers.  */
163         vlvgg   %v30,%r6,0
164         vlvgp   %v31,%r8,%r9
165         lghi    %r1,0           /* Zero out current len.  */
167         /* accept in v17 without zero.  */
168         vlr     %v19,%v17       /* Save first acc-part for a fast reload.  */
169         vzero   %v20            /* Zero for preparing acc-vector.  */
171         /* Align s to 16 byte.  */
172         risbg   %r0,%r2,60,128+63,0 /* Test if s is aligned and
173                                      %r0 = bits 60-63 'and' 15.  */
174         je      .Lslow_loop_str /* If s is aligned, loop aligned */
175         lghi    %r4,15
176         slr     %r4,%r0         /* Compute highest index to load (15-x).  */
177         vll     %v16,%r4,0(%r2) /* Load up to 16byte boundary (vll needs
178                                    highest index, remaining bytes are 0).  */
179         aghi    %r4,1           /* Work with loaded byte count.  */
180         vzero   %v21            /* Zero out global mask.  */
181         lghi    %r5,0           /* Set current len of accept-string to zero.  */
182         vfenezf %v18,%v16,%v16  /* Find zero in current string-part.  */
183         lghi    %r8,0           /* There is no zero in first accept-part.  */
184         vlgvb   %r6,%v18,7      /* Load byte index of zero or 16
185                                    if there is no zero.  */
186         clr     %r4,%r6         /* cc==1 if loaded byte count < zero-index.  */
187         locrl   %r6,%r4         /* Load on cc==1.  */
188         j       .Lslow_loop_acc
190         /* Process s in 16byte aligned loop.  */
191 .Lslow_next_str:
192         vlr     %v17,%v19       /* Load first part of accept (no zero).  */
193         algfr   %r1,%r4         /* Add loaded byte count to current len.  */
194 .Lslow_loop_str:
195         vl      %v16,0(%r1,%r2) /* Load search-string.  */
196         lghi    %r4,16          /* Loaded byte count is 16.  */
197         vzero   %v21            /* Zero out global mask.  */
198         lghi    %r5,0           /* Set current len of accept-string to zero.  */
199         vfenezf %v18,%v16,%v16  /* Find zero in current string-part.  */
200         lghi    %r8,0           /* There is no zero in first accept-part.  */
201         vlgvb   %r6,%v18,7      /* Load byte index of zero or 16 if no zero.  */
203 .Lslow_loop_acc:
204         vfaef   %v22,%v16,%v17,4 /* Create matching-mask (1 in mask ->
205                                     character matches any accepted character in
206                                     this accept-string-part) IN=0, RT=1.  */
207         vo      %v21,%v21,%v22  /* global-mask = global- | matching-mask.  */
208         vfenezf %v18,%v21,%v21  /* Find first zero in global-mask.  */
209         vlgvb   %r0,%v18,7      /* Get first found zero-index
210                                    (= first mismatch).  */
211         clrjl   %r0,%r6,.Lslow_next_acc /* Mismatch-index < min(lbc,zero-index)
212                                            -> Process this string-part
213                                               with next acc-part.  */
214         clrjhe  %r0,%r4,.Lslow_next_str /* Found-index >= loaded byte count
215                                            -> All loaded bytes are matching
216                                               any accept-character
217                                               and are not zero.  */
218         /* All bytes are matching any characters in accept-string
219            and search-string is fully processed (found-index == zero-index).  */
220 .Lslow_add_lbc_end:
221         algrk   %r2,%r1,%r0     /* Add matching characters to current len.  */
222         srlg    %r2,%r2,2       /* Convert byte-count to character-count.  */
223         /* Restore registers.  */
224         vlgvg   %r6,%v30,0
225         vlgvg   %r8,%v31,0
226         vlgvg   %r9,%v31,1
227         br      %r14
229 .Lslow_next_acc:
230         clijh   %r8,0,.Lslow_add_lbc_end /* There was a zero in last acc-part
231                                             -> Add found index to current len
232                                                and end.  */
233         vlbb    %v17,16(%r5,%r3),6 /* Load next accept part.  */
234         aghi    %r5,16          /* Increment current len of accept-string.  */
235         lcbb    %r9,0(%r5,%r3),6 /* Get loaded byte count of accept-string.  */
236         jo      .Lslow_next_acc_onbb /* Jump away if accept-string is
237                                         on block-boundary.  */
238 .Lslow_next_acc_notonbb:
239         vistrfs %v17,%v17       /* Fill with zeros after first zero.  */
240         jo      .Lslow_loop_acc /* No zero found -> no preparation needed.  */
242 .Lslow_next_acc_prepare_zero:
243         /* Zero in accept-part: fill zeros with first-accept-character.  */
244         vlgvf   %r8,%v17,0      /* Load first element of acc-part.  */
245         clije   %r8,0,.Lslow_add_lbc_end /* End if zero is first character
246                                              in this part of accept-string.  */
247         /* r8>0 -> zero found in this acc-part.  */
248         vrepf   %v18,%v17,0     /* Replicate first char across all chars.  */
249         vceqf   %v22,%v20,%v17  /* Create a mask (v22) of null chars
250                                    by comparing with 0 (v20).  */
251         vsel    %v17,%v18,%v17,%v22 /* Replace null chars with first char.  */
252         j       .Lslow_loop_acc /* Accept part is prepared -> process.  */
254 .Lslow_next_acc_onbb:
255         nill    %r9,65532       /* Recognize only fully loaded characters.  */
256         je      .Lslow_next_acc_onbb2 /* Reload vr, if we loaded no full
257                                           wchar_t.  */
258         vfenezf %v18,%v17,%v17  /* Find zero in loaded bytes of accept part.  */
259         vlgvb   %r8,%v18,7      /* Load byte index of zero.  */
260         clrjl   %r8,%r9,.Lslow_next_acc_notonbb /* Found a zero in loaded bytes
261                                                    -> Prepare vreg.  */
262 .Lslow_next_acc_onbb2:
263         vl      %v17,0(%r5,%r3) /* Load over boundary ...  */
264         lghi    %r8,0           /* r8=0 -> no zero in this part of acc,
265                                    check for zero is in jump-target.  */
266         j       .Lslow_next_acc_notonbb /* ... and search for zero in
267                                            fully loaded vreg again.  */
268 .Lfallback:
269         jg      WCSSPN_C
270 END(WCSSPN_Z13)
272 # if ! HAVE_WCSSPN_IFUNC
273 strong_alias (WCSSPN_Z13, wcsspn)
274 # endif
276 # if defined HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT \
277         && defined SHARED && IS_IN (libc)
278 strong_alias (WCSSPN_Z13, __GI_wcsspn)
279 # endif
280 #endif