Skip to content

Commit

Permalink
Always use any fast available msb/lsb method
Browse files Browse the repository at this point in the history
Some platforms have a fast way to get the msb but not the lsb; others,
more rarely, have the reverse.  But using a few shift and the like
instructions allows us to reduce either instance to terms of the other.

This commit causes any available fast method to be used by turning the
non-available case into the available one
  • Loading branch information
khwilliamson committed Jul 20, 2021
1 parent f32cf51 commit 99533b6
Showing 1 changed file with 49 additions and 0 deletions.
49 changes: 49 additions & 0 deletions inline.h
Expand Up @@ -775,10 +775,12 @@ Perl_lsbit_pos64(U64 word)
* this info, use that */

# if defined(PERL_CTZ_64)
# define PERL_HAS_FAST_GET_LSB_POS64

return (unsigned) PERL_CTZ_64(word);

# elif U64SIZE == 8 && defined(_MSC_VER) && _MSC_VER >= 1400
# define PERL_HAS_FAST_GET_LSB_POS64

{
unsigned long index;
Expand All @@ -787,6 +789,7 @@ Perl_lsbit_pos64(U64 word)
}

# elif defined(PERL_FFS64)
# define PERL_HAS_FAST_GET_LSB_POS64

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

Expand Down Expand Up @@ -831,10 +834,12 @@ Perl_lsbit_pos32(U32 word)
ASSUME(word != 0);

#if defined(PERL_CTZ_32)
# define PERL_HAS_FAST_GET_LSB_POS32

return (unsigned) PERL_CTZ_32(word);

#elif U32SIZE == 4 && defined(_MSC_VER) && _MSC_VER >= 1400
# define PERL_HAS_FAST_GET_LSB_POS32

{
unsigned long index;
Expand All @@ -843,6 +848,7 @@ Perl_lsbit_pos32(U32 word)
}

#elif defined(PERL_FFS32)
# define PERL_HAS_FAST_GET_LSB_POS32

return PERL_FFS32(word) - 1;

Expand Down Expand Up @@ -872,10 +878,12 @@ Perl_msbit_pos64(U64 word)
* this, use that */

# if defined(PERL_CLZ_64)
# define PERL_HAS_FAST_GET_MSB_POS64

return (unsigned) LZC_TO_MSBIT_POS_(U64, PERL_CLZ_64(word));

# elif U64SIZE == 8 && defined(_WIN64) && defined(_MSC_VER) && _MSC_VER >= 1400
# define PERL_HAS_FAST_GET_MSB_POS64

{
unsigned long index;
Expand Down Expand Up @@ -927,10 +935,12 @@ Perl_msbit_pos32(U32 word)
ASSUME(word != 0);

#if defined(PERL_CLZ_32)
# define PERL_HAS_FAST_GET_MSB_POS32

return (unsigned) LZC_TO_MSBIT_POS_(U32, PERL_CLZ_32(word));

#elif U32SIZE == 4 && defined(_MSC_VER) && _MSC_VER >= 1400
# define PERL_HAS_FAST_GET_MSB_POS32

{
unsigned long index;
Expand Down Expand Up @@ -964,11 +974,29 @@ Perl_single_1bit_pos64(U64 word)
ASSUME(isPOWER_OF_2(word));
# endif

/* The only set bit is both the most and least significant bit. If we have
* a fast way of finding either one, use that.
*
* It may appear at first glance that those functions call this one, but
* they don't if the corresponding #define is set */

# ifdef PERL_HAS_FAST_GET_MSB_POS64

return msbit_pos64(word);

# elif defined(PERL_HAS_FAST_GET_LSB_POS64)

return lsbit_pos64(word);

# else

/* The position of the only set bit in a word can be quickly calculated
* using deBruijn sequences. See for example
* https://en.wikipedia.org/wiki/De_Bruijn_sequence */
return PL_deBruijn_bitpos_tab64[(word * PERL_deBruijnMagic64_)
>> PERL_deBruijnShift64_];
# endif

}

#endif
Expand All @@ -982,9 +1010,30 @@ Perl_single_1bit_pos32(U32 word)
#ifdef PERL_CORE /* macro not exported */
ASSUME(isPOWER_OF_2(word));
#endif
#ifdef PERL_HAS_FAST_GET_MSB_POS32

return msbit_pos32(word);

#elif defined(PERL_HAS_FAST_GET_LSB_POS32)

return lsbit_pos32(word);

/* Unlikely, but possible for the platform to have a wider fast operation but
* not a narrower one. But handle the case by widening the parameter size */
#elif defined(PERL_HAS_FAST_GET_MSB_POS64)

return msbit_pos64(word);

#elif defined(PERL_HAS_FAST_GET_LSB_POS64)

return lsbit_pos64(word);

#else

return PL_deBruijn_bitpos_tab32[(word * PERL_deBruijnMagic32_)
>> PERL_deBruijnShift32_];
#endif

}

#ifndef EBCDIC
Expand Down

0 comments on commit 99533b6

Please sign in to comment.