Advertisement
wojiaocbj

strstr

Sep 4th, 2022
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.05 KB | None | 0 0
  1. /*
  2.  *  Copyright (C) 2009-2010 Intel Corporation.
  3.  *
  4.  *  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  5.  */
  6.  
  7. /***
  8. *strstr.c - search for one string inside another
  9. *
  10. *Purpose:
  11. *       defines strstr() - search for one string inside another
  12. *
  13. *******************************************************************************/
  14.  
  15. #include <vcruntime_internal.h>
  16. #include <intrin.h>
  17. #include <limits.h>
  18.  
  19. // These flags select the operation performed by _mm_cmp?str? functions.
  20.  
  21. // PCMPxSTRx character type
  22. #define f_pcmp_ub   0x00
  23. #define f_pcmp_uw   0x01
  24. #define f_pcmp_sb   0x02
  25. #define f_pcmp_sw   0x03
  26. // PCMPxSTRx aggregation operation
  27. #define f_pcmp_ea   0x00
  28. #define f_pcmp_rng  0x04
  29. #define f_pcmp_ee   0x08
  30. #define f_pcmp_eo   0x0C
  31. // PCMPxSTRx result polarity
  32. #define f_pcmp_pp   0x00
  33. #define f_pcmp_np   0x10
  34. #define f_pcmp_mp   0x20
  35. #define f_pcmp_mn   0x30
  36. // PCMPxSTRI index order
  37. #define f_pcmp_ls   0x00
  38. #define f_pcmp_ms   0x40
  39. // PCMPxSTRM result unit size
  40. #define f_pcmp_bit  0x00
  41. #define f_pcmp_byte 0x40
  42.  
  43. // Define flag combinations to use.
  44. #define f_srch_sub (f_pcmp_ub | f_pcmp_eo | f_pcmp_pp | f_pcmp_ls)
  45.  
  46. #define XMM_SIZE sizeof(__m128i)
  47. #define XMM_CHARS (XMM_SIZE / sizeof(char))
  48. #define XMM_OFFSET(p) ((sizeof(__m128i) - 1) & (intptr_t)(p))
  49. #define XMM_ALIGNED(p) (0 == XMM_OFFSET(p))
  50.  
  51. #define PAGE_SIZE ((intptr_t)0x1000)
  52. #define PAGE_OFFSET(p) ((PAGE_SIZE-1) & (intptr_t)(p))
  53. #define XMM_PAGE_SAFE(p) (PAGE_OFFSET(p) <= (PAGE_SIZE - XMM_SIZE))
  54.  
  55. /***
  56. *char *strstr(string1, string2) - search for string2 in string1
  57. *
  58. *Purpose:
  59. *       finds the first occurrence of string2 in string1
  60. *
  61. *Entry:
  62. *       char *string1 - string to search in
  63. *       char *string2 - string to search for
  64. *
  65. *Exit:
  66. *       returns a pointer to the first occurrence of string2 in
  67. *       string1, or NULL if string2 does not occur in string1
  68. *
  69. *Uses:
  70. *
  71. *Exceptions:
  72. *
  73. *******************************************************************************/
  74.  
  75. _Check_return_ _Ret_maybenull_
  76. char * __cdecl strstr (
  77.     _In_z_ const char * str1,
  78.     _In_z_ const char * str2
  79.         )
  80. {
  81.     const char *stmp1, *stmp2;
  82.     __m128i zero, pattern, characters1, characters2;
  83.  
  84.     // An empty search string matches everything.
  85.     if (0 == *str2)
  86.         return (char *)str1;
  87.  
  88.     if (__isa_available < __ISA_AVAILABLE_SSE42)
  89.     {
  90.         unsigned mask;
  91.         unsigned long offset;
  92.  
  93.         // Build search pattern and zero pattern. Search pattern is
  94.         // XMMWORD with the initial character of the search string
  95.         // in every position. Zero pattern has a zero termination
  96.         // character in every position.
  97.  
  98.         pattern = _mm_cvtsi32_si128((unsigned char)str2[0] | ((unsigned char)str2[0] << CHAR_BIT));
  99.         pattern = _mm_shufflelo_epi16(pattern, 0);
  100.         pattern = _mm_shuffle_epi32(pattern, 0);
  101.         zero = _mm_set1_epi32(0);
  102.  
  103.         // Main loop for searching str1. We look for the next character that
  104.         // matches the first character of the search string then compare to
  105.         // the end of the search string.
  106.  
  107.         for (;;)
  108.         {
  109.             // If string pointer is page safe look for the next possible match
  110.             // or end. If none are found we can immediately check the next block,
  111.             // otherwise set the string pointer to the address of the significant
  112.             // character.
  113.  
  114.             if (XMM_PAGE_SAFE(str1))
  115.             {
  116.                 characters1 = _mm_loadu_si128((__m128i*)str1);
  117.                 characters2 = _mm_cmpeq_epi8(characters1, zero);
  118.                 characters1 = _mm_cmpeq_epi8(characters1, pattern);
  119.                 characters1 = _mm_or_si128(characters1, characters2);
  120.                 mask = _mm_movemask_epi8(characters1);
  121.  
  122.                 // If no character match or end found try next XMMWORD.
  123.  
  124.                 if (0 == mask)
  125.                 {
  126.                     str1 += XMM_SIZE;
  127.                     continue;
  128.                 }
  129.  
  130.                 // Advance str1 pointer to next possible match or end.
  131.  
  132.                 _BitScanForward(&offset, mask);
  133.                 str1 += offset;
  134.             }
  135.  
  136.             // If at the end of str1, then no match found.
  137.  
  138.             if (0 == str1[0]) return NULL;
  139.  
  140.             // If a first-character match is found compare strings to look for
  141.             // a complete match.
  142.  
  143.             if (str2[0] == str1[0])
  144.             {
  145.                 stmp1 = str1;
  146.                 stmp2 = str2;
  147.                 for (;;)
  148.                 {
  149.                     // If search string is aligned and searched string is page-safe
  150.                     // check a character block for differences or the end of string2.
  151.                     // If nothing is found then go immediately to the next block.
  152.  
  153.                     if (XMM_PAGE_SAFE(stmp2) && XMM_PAGE_SAFE(stmp1))
  154.                     {
  155.                         characters1 = _mm_loadu_si128((__m128i*)stmp1);
  156.                         characters2 = _mm_loadu_si128((__m128i*)stmp2);
  157.                         characters1 = _mm_cmpeq_epi8(characters1, characters2);
  158.                         characters2 = _mm_cmpeq_epi8(characters2, zero);
  159.                         characters1 = _mm_cmpeq_epi8(characters1, zero);
  160.                         characters2 = _mm_or_si128(characters1, characters2);
  161.                         mask = _mm_movemask_epi8(characters2);
  162.  
  163.                         // If no character difference or end found try next XMMWORD.
  164.  
  165.                         if (0 == mask)
  166.                         {
  167.                             stmp1 += XMM_SIZE;
  168.                             stmp2 += XMM_SIZE;
  169.                             continue;
  170.                         }
  171.  
  172.                         // Advance string pointers to next significant character.
  173.  
  174.                         _BitScanForward(&offset, mask);
  175.                         stmp1 += offset;
  176.                         stmp2 += offset;
  177.                     }
  178.  
  179.                     // If we've reached the end of str2 then a match has been found.
  180.  
  181.                     if (0 == stmp2[0]) return (char *)str1;
  182.  
  183.                     // If we've reached a difference then no match was found.
  184.  
  185.                     if (stmp1[0] != stmp2[0]) break;
  186.  
  187.                     // Otherwise advance to next character and try again.
  188.  
  189.                     ++stmp1;
  190.                     ++stmp2;
  191.                 }
  192.             }
  193.  
  194.             // Current character wasn't a match, try next character.
  195.  
  196.             ++str1;
  197.         }
  198.     }
  199.     else
  200.     {
  201.         // SSE 4.2 supported, search & compare 16 bytes at a time if possible.
  202.         char c;
  203.         unsigned i;
  204.  
  205.         // Load XMM with first characters of str2.
  206.         if (XMM_PAGE_SAFE(str2))
  207.         {
  208.             pattern = _mm_loadu_si128((__m128i*)str2);
  209.         }
  210.         else
  211.         {
  212.             pattern = _mm_set1_epi32(0);
  213.             c = *(stmp2 = str2);
  214.             for (i = 0; i < XMM_CHARS; ++i)
  215.             {
  216.                 pattern = _mm_srli_si128(pattern, sizeof(char));
  217.                 pattern = _mm_insert_epi8(pattern, c, (XMM_CHARS-1));
  218.                 if (0 != c) c = *++stmp2;
  219.             }
  220.         }
  221.  
  222.         for(;;)
  223.         {
  224.             // Check for partial match, if none step forward and continue.
  225.             if (XMM_PAGE_SAFE(str1))
  226.             {
  227.                 characters1 = _mm_loadu_si128((__m128i*)str1);
  228.                 // If no potential match or end found, try next XMMWORD.
  229.                 if (_mm_cmpistra(pattern, characters1, f_srch_sub))
  230.                 {
  231.                     str1 += XMM_CHARS;
  232.                     continue;
  233.                 }
  234.                 // If end found there was no match.
  235.                 else if (!_mm_cmpistrc(pattern, characters1, f_srch_sub))
  236.                 {
  237.                     return NULL;
  238.                 }
  239.  
  240.                 // Get position of potential match.
  241.                 str1 += _mm_cmpistri(pattern, characters1, f_srch_sub);
  242.             }
  243.             else
  244.             {
  245.                 // If end of string found there was no match.
  246.                 if (0 == *str1)
  247.                 {
  248.                     return NULL;
  249.                 }
  250.  
  251.                 // If current character doesn't match first character
  252.                 // of search string try next character.
  253.                 if (*str1 != *str2)
  254.                 {
  255.                     ++str1;
  256.                     continue;
  257.                 }
  258.             }
  259.  
  260.             // Potential match, compare to check for full match.
  261.             stmp1 = str1;
  262.             stmp2 = str2;
  263.             for (;;)
  264.             {
  265.               // If next XMMWORD is page-safe for each string
  266.               // do a XMMWORD comparison.
  267.               if (XMM_PAGE_SAFE(stmp1) && XMM_PAGE_SAFE(stmp2))
  268.               {
  269.                   characters1 = _mm_loadu_si128((__m128i*)stmp1);
  270.                   characters2 = _mm_loadu_si128((__m128i*)stmp2);
  271.  
  272.                   // If unequal then no match found.
  273.                   if (!_mm_cmpistro(characters2, characters1, f_srch_sub))
  274.                   {
  275.                       break;
  276.                   }
  277.  
  278.                   // If end of search string then match found.
  279.                   else if (_mm_cmpistrs(characters2, characters1, f_srch_sub))
  280.                   {
  281.                       return (char *)str1;
  282.                   }
  283.  
  284.                   stmp1 += XMM_CHARS;
  285.                   stmp2 += XMM_CHARS;
  286.               }
  287.  
  288.               // Compare next character.
  289.               else
  290.               {
  291.                   // If end of search string then match found.
  292.                   if (0 == *stmp2)
  293.                   {
  294.                       return (char *)str1;
  295.                   }
  296.  
  297.                   // If unequal then no match found.
  298.                   if (*stmp1 != *stmp2)
  299.                   {
  300.                       break;
  301.                   }
  302.  
  303.                   // Character matched - try next character.
  304.                   ++stmp1;
  305.                   ++stmp2;
  306.               }
  307.           }
  308.  
  309.           // Match not found at current position, try next.
  310.           ++str1;
  311.         }
  312.     }
  313. }
  314.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement