Skip to content

Commit

Permalink
Use ffs(), ffsl() for lsb_pos, if available
Browse files Browse the repository at this point in the history
ffs() is a POSIX function that serves to find the lsb of a word.  It
should be faster than anything we hand-roll, but slower than any
available intrinsics that the previous commits use; so this commit looks
for it only if they aren't available.

Some platforms have an equivalent ffsl() for longs, which we use if the
word is long-sized.
  • Loading branch information
khwilliamson committed Jul 20, 2021
1 parent 012129c commit f32cf51
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions inline.h
Expand Up @@ -731,6 +731,21 @@ Perl_is_utf8_invariant_string_loc(const U8* const s, STRLEN len, const U8 ** ep)
# endif
#endif

#if U32SIZE == INTSIZE && defined(HAS_FFS)
# define PERL_FFS32 ffs
#elif U32SIZE == LONGSIZE && defined(HAS_FFSL)
# define PERL_FFS32 ffsl
#endif
#ifdef HAS_QUAD
# if U64SIZE == INTSIZE && defined(HAS_FFS)
# define PERL_FFS64 ffs
# elif U64SIZE == LONGSIZE && defined(HAS_FFSL)
# define PERL_FFS64 ffsl
# elif U64SIZE == LONGLONGSIZE && defined(HAS_FFSLL)
# define PERL_FFS64 ffsll
# endif
#endif

#if defined(_MSC_VER) && _MSC_VER >= 1400
# include <intrin.h>
# pragma intrinsic(_BitScanForward)
Expand Down Expand Up @@ -771,6 +786,10 @@ Perl_lsbit_pos64(U64 word)
return (unsigned)index;
}

# elif defined(PERL_FFS64)

return PERL_FFS64(word) - 1; /* ffs() returns bit position indexed from 1 */

# else

/* Here, we didn't find a fast method for finding the lsb. Fall back to
Expand Down Expand Up @@ -823,6 +842,10 @@ Perl_lsbit_pos32(U32 word)
return (unsigned)index;
}

#elif defined(PERL_FFS32)

return PERL_FFS32(word) - 1;

#else

return single_1bit_pos32(word & (~word + 1));
Expand Down

0 comments on commit f32cf51

Please sign in to comment.