1 /*************************************************
2 *      Perl-Compatible Regular Expressions       *
3 *************************************************/
4 
5 /* PCRE is a library of functions to support regular expressions whose syntax
6 and semantics are as close as possible to those of the Perl 5 language.
7 
8                        Written by Philip Hazel
9             This module by Zoltan Herczeg and Sebastian Pop
10      Original API code Copyright (c) 1997-2012 University of Cambridge
11           New API code Copyright (c) 2016-2019 University of Cambridge
12 
13 -----------------------------------------------------------------------------
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions are met:
16 
17     * Redistributions of source code must retain the above copyright notice,
18       this list of conditions and the following disclaimer.
19 
20     * Redistributions in binary form must reproduce the above copyright
21       notice, this list of conditions and the following disclaimer in the
22       documentation and/or other materials provided with the distribution.
23 
24     * Neither the name of the University of Cambridge nor the names of its
25       contributors may be used to endorse or promote products derived from
26       this software without specific prior written permission.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 POSSIBILITY OF SUCH DAMAGE.
39 -----------------------------------------------------------------------------
40 */
41 
42 # if defined(FFCS)
43 #  if defined(FF_UTF)
44 #   define FF_FUN ffcs_utf
45 #  else
46 #   define FF_FUN ffcs
47 #  endif
48 
49 # elif defined(FFCS_2)
50 #  if defined(FF_UTF)
51 #   define FF_FUN ffcs_2_utf
52 #  else
53 #   define FF_FUN ffcs_2
54 #  endif
55 
56 # elif defined(FFCS_MASK)
57 #  if defined(FF_UTF)
58 #   define FF_FUN ffcs_mask_utf
59 #  else
60 #   define FF_FUN ffcs_mask
61 #  endif
62 
63 # elif defined(FFCPS_0)
64 #  if defined (FF_UTF)
65 #   define FF_FUN ffcps_0_utf
66 #  else
67 #   define FF_FUN ffcps_0
68 #  endif
69 
70 # elif defined (FFCPS_1)
71 #  if defined (FF_UTF)
72 #   define FF_FUN ffcps_1_utf
73 #  else
74 #   define FF_FUN ffcps_1
75 #  endif
76 
77 # elif defined (FFCPS_DEFAULT)
78 #  if defined (FF_UTF)
79 #   define FF_FUN ffcps_default_utf
80 #  else
81 #   define FF_FUN ffcps_default
82 #  endif
83 # endif
84 
FF_FUN(sljit_u8 * str_end,sljit_u8 * str_ptr,sljit_uw offs1,sljit_uw offs2,sljit_uw chars)85 static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 *str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars)
86 #undef FF_FUN
87 {
88 quad_word qw;
89 int_char ic;
90 
91 SLJIT_UNUSED_ARG(offs1);
92 SLJIT_UNUSED_ARG(offs2);
93 
94 ic.x = chars;
95 
96 #if defined(FFCS)
97 sljit_u8 c1 = ic.c.c1;
98 vect_t vc1 = VDUPQ(c1);
99 
100 #elif defined(FFCS_2)
101 sljit_u8 c1 = ic.c.c1;
102 vect_t vc1 = VDUPQ(c1);
103 sljit_u8 c2 = ic.c.c2;
104 vect_t vc2 = VDUPQ(c2);
105 
106 #elif defined(FFCS_MASK)
107 sljit_u8 c1 = ic.c.c1;
108 vect_t vc1 = VDUPQ(c1);
109 sljit_u8 mask = ic.c.c2;
110 vect_t vmask = VDUPQ(mask);
111 #endif
112 
113 #if defined(FFCPS)
114 compare_type compare1_type = compare_match1;
115 compare_type compare2_type = compare_match1;
116 vect_t cmp1a, cmp1b, cmp2a, cmp2b;
117 const sljit_u32 diff = IN_UCHARS(offs1 - offs2);
118 PCRE2_UCHAR char1a = ic.c.c1;
119 PCRE2_UCHAR char2a = ic.c.c3;
120 
121 # ifdef FFCPS_CHAR1A2A
122 cmp1a = VDUPQ(char1a);
123 cmp2a = VDUPQ(char2a);
124 cmp1b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
125 cmp2b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
126 # else
127 PCRE2_UCHAR char1b = ic.c.c2;
128 PCRE2_UCHAR char2b = ic.c.c4;
129 if (char1a == char1b)
130   {
131   cmp1a = VDUPQ(char1a);
132   cmp1b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
133   }
134 else
135   {
136   sljit_u32 bit1 = char1a ^ char1b;
137   if (is_powerof2(bit1))
138     {
139     compare1_type = compare_match1i;
140     cmp1a = VDUPQ(char1a | bit1);
141     cmp1b = VDUPQ(bit1);
142     }
143   else
144     {
145     compare1_type = compare_match2;
146     cmp1a = VDUPQ(char1a);
147     cmp1b = VDUPQ(char1b);
148     }
149   }
150 
151 if (char2a == char2b)
152   {
153   cmp2a = VDUPQ(char2a);
154   cmp2b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
155   }
156 else
157   {
158   sljit_u32 bit2 = char2a ^ char2b;
159   if (is_powerof2(bit2))
160     {
161     compare2_type = compare_match1i;
162     cmp2a = VDUPQ(char2a | bit2);
163     cmp2b = VDUPQ(bit2);
164     }
165   else
166     {
167     compare2_type = compare_match2;
168     cmp2a = VDUPQ(char2a);
169     cmp2b = VDUPQ(char2b);
170     }
171   }
172 # endif
173 
174 str_ptr += IN_UCHARS(offs1);
175 #endif
176 
177 #if PCRE2_CODE_UNIT_WIDTH != 8
178 vect_t char_mask = VDUPQ(0xff);
179 #endif
180 
181 #if defined(FF_UTF)
182 restart:;
183 #endif
184 
185 #if defined(FFCPS)
186 if (str_ptr >= str_end)
187   return NULL;
188 sljit_u8 *p1 = str_ptr - diff;
189 #endif
190 sljit_s32 align_offset = ((uint64_t)str_ptr & 0xf);
191 str_ptr = (sljit_u8 *) ((uint64_t)str_ptr & ~0xf);
192 vect_t data = VLD1Q(str_ptr);
193 #if PCRE2_CODE_UNIT_WIDTH != 8
194 data = VANDQ(data, char_mask);
195 #endif
196 
197 #if defined(FFCS)
198 vect_t eq = VCEQQ(data, vc1);
199 
200 #elif defined(FFCS_2)
201 vect_t eq1 = VCEQQ(data, vc1);
202 vect_t eq2 = VCEQQ(data, vc2);
203 vect_t eq = VORRQ(eq1, eq2);
204 
205 #elif defined(FFCS_MASK)
206 vect_t eq = VORRQ(data, vmask);
207 eq = VCEQQ(eq, vc1);
208 
209 #elif defined(FFCPS)
210 # if defined(FFCPS_DIFF1)
211 vect_t prev_data = data;
212 # endif
213 
214 vect_t data2;
215 if (p1 < str_ptr)
216   {
217   data2 = VLD1Q(str_ptr - diff);
218 #if PCRE2_CODE_UNIT_WIDTH != 8
219   data2 = VANDQ(data2, char_mask);
220 #endif
221   }
222 else
223   data2 = shift_left_n_lanes(data, offs1 - offs2);
224 
225 if (compare1_type == compare_match1)
226   data = VCEQQ(data, cmp1a);
227 else
228   data = fast_forward_char_pair_compare(compare1_type, data, cmp1a, cmp1b);
229 
230 if (compare2_type == compare_match1)
231   data2 = VCEQQ(data2, cmp2a);
232 else
233   data2 = fast_forward_char_pair_compare(compare2_type, data2, cmp2a, cmp2b);
234 
235 vect_t eq = VANDQ(data, data2);
236 #endif
237 
238 VST1Q(qw.mem, eq);
239 /* Ignore matches before the first STR_PTR. */
240 if (align_offset < 8)
241   {
242   qw.dw[0] >>= align_offset * 8;
243   if (qw.dw[0])
244     {
245     str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8;
246     goto match;
247     }
248   if (qw.dw[1])
249     {
250     str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
251     goto match;
252     }
253   }
254 else
255   {
256   qw.dw[1] >>= (align_offset - 8) * 8;
257   if (qw.dw[1])
258     {
259     str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8;
260     goto match;
261     }
262   }
263 str_ptr += 16;
264 
265 while (str_ptr < str_end)
266   {
267   vect_t orig_data = VLD1Q(str_ptr);
268 #if PCRE2_CODE_UNIT_WIDTH != 8
269   orig_data = VANDQ(orig_data, char_mask);
270 #endif
271   data = orig_data;
272 
273 #if defined(FFCS)
274   eq = VCEQQ(data, vc1);
275 
276 #elif defined(FFCS_2)
277   eq1 = VCEQQ(data, vc1);
278   eq2 = VCEQQ(data, vc2);
279   eq = VORRQ(eq1, eq2);
280 
281 #elif defined(FFCS_MASK)
282   eq = VORRQ(data, vmask);
283   eq = VCEQQ(eq, vc1);
284 #endif
285 
286 #if defined(FFCPS)
287 # if defined (FFCPS_DIFF1)
288   data2 = VEXTQ(prev_data, data, VECTOR_FACTOR - 1);
289 # else
290   data2 = VLD1Q(str_ptr - diff);
291 #  if PCRE2_CODE_UNIT_WIDTH != 8
292   data2 = VANDQ(data2, char_mask);
293 #  endif
294 # endif
295 
296 # ifdef FFCPS_CHAR1A2A
297   data = VCEQQ(data, cmp1a);
298   data2 = VCEQQ(data2, cmp2a);
299 # else
300   if (compare1_type == compare_match1)
301     data = VCEQQ(data, cmp1a);
302   else
303     data = fast_forward_char_pair_compare(compare1_type, data, cmp1a, cmp1b);
304   if (compare2_type == compare_match1)
305     data2 = VCEQQ(data2, cmp2a);
306   else
307     data2 = fast_forward_char_pair_compare(compare2_type, data2, cmp2a, cmp2b);
308 # endif
309 
310   eq = VANDQ(data, data2);
311 #endif
312 
313   VST1Q(qw.mem, eq);
314   if (qw.dw[0])
315     str_ptr += __builtin_ctzll(qw.dw[0]) / 8;
316   else if (qw.dw[1])
317     str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
318   else {
319     str_ptr += 16;
320 #if defined (FFCPS_DIFF1)
321     prev_data = orig_data;
322 #endif
323     continue;
324   }
325 
326 match:;
327   if (str_ptr >= str_end)
328     /* Failed match. */
329     return NULL;
330 
331 #if defined(FF_UTF)
332   if (utf_continue((PCRE2_SPTR)str_ptr - offs1))
333     {
334     /* Not a match. */
335     str_ptr += IN_UCHARS(1);
336     goto restart;
337     }
338 #endif
339 
340   /* Match. */
341 #if defined (FFCPS)
342   str_ptr -= IN_UCHARS(offs1);
343 #endif
344   return str_ptr;
345   }
346 
347 /* Failed match. */
348 return NULL;
349 }
350