[PATCH 10/17] string: Improve generic memchr

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Thu Sep 22 17:51:28 GMT 2022



On 19/09/22 18:59, Noah Goldstein wrote:
> On Mon, Sep 19, 2022 at 12:17 PM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>
>>
>>
>> On 03/09/22 00:47, Noah Goldstein wrote:
>>
>>>>
>>>> -  longword_ptr = (const longword *) char_ptr;
>>>> +  /* Compute the address of the word containing the last byte. */
>>>> +  const op_t *lword = word_containing (lbyte);
>>>>
>>>> -  /* All these elucidatory comments refer to 4-byte longwords,
>>>> -     but the theory applies equally well to any size longwords.  */
>>>> +  /* Read the first word, but munge it so that bytes before the array
>>>> +     will not match goal.  */
>>>> +  const op_t * word_ptr = word_containing (s);
>>>> +  op_t word = (*word_ptr | before_mask) ^ (repeated_c & before_mask);
>>>
>>> Why do you xor with repeated_c & before_mask here?
>>>
>>> Doesn't the has_eq(word, repeated_c) do that?
>>
>> For the case of c_in being 0xff, since for this case or with before_mask
>> will make has_eq to return early.  The test-memchr does not trigger it,
>> but test-memccpy does fail without the XOR.
> 
> I see. Since a match in the first several bytes is fairly common
> maybe it would be better to special case the first iteration and just do
> 
> has_eq(word, repeated_c) >> (CHAR_BIT * (addr % sizeof(addr)).
> The result can just be added to `s` if there is a match.

I think you mean something like:

  has_eq (word >> (CHAR_BIT * (s % sizeof(op_t)), repeated_c) 

Since has_eq returns _Bool.  However in this case we will need to shift
the repeated_c as well, and it will bleed endianess definition (the shift
direction) on generic implementation.  On both cases not sure if this will
be a gain.

Maybe we can also parametrize the first check:

  static inline _Bool
  has_eq_first (op_t *word, const op_t *word_ptr, op_t repeated_c, 
                op_t before_mask)
  {
    *word = (*word_ptr | before_mask) ^ (repeated_c & before_mask);
    return has_eq (*word, repeated_c);
  } 

  [...]

  op_t word;
  if (!has_eq_first (&word, word_ptr, repeated_c, before_mask))
    {
      do
        {
          if (word_ptr == lword)
            return NULL;
          word = *++word_ptr;
        }
      while (!has_eq (word, repeated_c));
    }

If the architecture has a better strategy to check.  But I also not sure
if this would indeed yield any improvement in the end.


More information about the Libc-alpha mailing list