Bit Operations

<kernel v5.10>

Bit 관련 매크로

BITS_PER_LONG

include/asm-generic/bitsperlong.h”

1#ifdef CONFIG_64BIT
2#define BITS_PER_LONG 64
3#else
4#define BITS_PER_LONG 32
5#endif /* CONFIG_64BIT */

long 타입에서 사용될 수 있는 비트 수

 

BITS_PER_LONG_LONG

include/asm-generic/bitsperlong.h”

1#ifndef BITS_PER_LONG_LONG
2#define BITS_PER_LONG_LONG 64
3#endif

long long 타입에서 사용될 수 있는 비트 수

 

BIT_ULL()

include/linux/bits.h

1#define BIT_ULL(nr)             (ULL(1) << (nr))

nr 비트에 해당하는 unsigned long long 값을 반환한다.

  • nr=0~63 비트까지 지정할 수 있다.
  • 예)
    • nr=0 -> 1
    • nr=1 -> 2
    • ..
    • nr=63 -> 0x8000_0000_0000_0000

 

BIT_MASK()

include/linux/bits.h

1#define BIT_MASK(nr)            (UL(1) << ((nr) % BITS_PER_LONG))

unsigned long 값(또는 배열)에서 nr 비트에 해당하는 비트를 추출할 목적의 비트 마스크를 만든다.

  • nr=0~
  • 예)
    • nr=0 -> 1
    • nr=1 -> 2
    • ..
    • nr=63 -> 0x8000_0000 (32 bit 기준), 0x8000_0000_0000_0000 (64 bit 기준)
    • nr=64 -> 1

 

 BIT_WORD()

include/linux/bits.h

1#define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)

@nr 비트가 속한 unsigned long 비트맵 배열의 인덱스 번호 (0부터 시작)

  • nr=0~
  • 예)
    • nr=0 -> 0
    • nr=31 -> 0
    • nr=32 -> 1 (32bit 기준), 0 (64bit 기준)
    • nr=63 -> 1 (32bit 기준), 0 (64bit 기준)
    • nr=64 -> 2 (32bit 기준), 1 (64bit 기준)
    • nr=95 -> 2 (32bit 기준), 1 (64bit 기준)
    • nr=96 -> 3 (32bit 기준), 1 (64bit 기준)
    • nr=127 -> 3 (32bit 기준), 1 (64bit 기준)
    • nr=128 -> 4 (32bit 기준), 2 (64bit 기준)
    • nr=159 -> 4 (32bit 기준), 2 (64bit 기준)
    • nr=160 -> 5 (32bit 기준), 2 (64bit 기준)
    • nr=191 -> 5 (32bit 기준), 2 (64bit 기준)

 

BIT_ULL_MASK()

include/linux/bits.h

1#define BIT_ULL_MASK(nr)        (ULL(1) << ((nr) % BITS_PER_LONG_LONG))

unsigned long long 값(또는 배열)에서 nr 비트에 해당하는 비트를 추출할 목적의 비트 마스크를 만든다.

  • nr=0~
  • 예)
    • nr=0 -> 1
    • nr=1 -> 2
    • ..
    • nr=63 -> 0x8000_0000_0000_0000 (32 bit 및 64 bit 동일)
    • nr=64 -> 1

 

BIT_ULL_WORD()

include/linux/bits.h

1#define BIT_ULL_WORD(nr)        ((nr) / BITS_PER_LONG_LONG)

@nr 비트가 속한 unsigned long long 비트맵 배열에 대한 인덱스 번호 (0부터 시작)

  • nr=0~
  • 예)
    • nr=0 -> 0
    • nr=63 -> 0
    • nr=64 -> 1
    • nr=127 -> 1
    • nr=128 -> 2
    • nr=191 -> 2

 

BITS_PER_BYTE

include/linux/bits.h

1#define BITS_PER_BYTE           8

byte 타입에서 사용될 수 있는 비트 수

 


Bit Operations

API들

Search

  • fls()
  • __fls()
  • ffs()
  • __ffs()
  • ffz()
  • fls_long()

 

Iteration

  • for_each_set_bit(bit, addr, size)
    • size 비트 한도의 addr 값에서 셋(1) 비트 수 만큼 루프를 돈다.
    • 예) addr=0x3f0, size=8
      • 4번의 루프(bit=4, 5, 6, 7)
  • for_each_set_bit_from(bit, addr, size)
    • for_each_set_bit()와 유사하지만 시작 비트를 지정한 곳에서 출발한다.
    • 예) addr=0x3f0, size=8, bit=5
      • 3번의 루프(bit=5, 6, 7)
  • for_each_clear_bit(bit, addr, size)
    • size 비트 한도의 addr 값에서 클리어(0) 비트 수 만큼 루프를 돈다.
    • 예) addr=0xfff0, size=8
      • 4번의 루프(bit=0, 1, 2, 3)
  • for_each_clear_bit_from(bit, addr, size)
    • for_each_set_bit()와 유사하지만 시작 비트를 지정한 곳에서 출발한다.
    • 예) addr=0x3f0, size=8, bit=1
      • 3번의 루프(bit=1, 2, 3)

 

rotate

  • rol64()
  • ror64()
  • rol32()
  • ror32()
  • rol16()
  • ror16()
  • rol8()
  • ror8()

 

atomic

  • set_bit()
  • test_bit()
  • clear_bit()
  • change_bit()
  • test_and_set_bit()
  • test_and_clear_bit()
  • test_and_change_bit()
  • find_first_zero_bit()
  • find_next_zero_bit()
  • find_last_zero_bit()
  • find_first_bit()
  • find_next_bit()
  • find_last_bit()

 

lock

  • test_and_set_bit_lock()
  • clear_bit_unlock()
    • __clear_bit_unlock()
  • clear_bit_unlock_is_negative_byte()

 

le(little endian)

  • find_next_zero_bit_le()
  • find_next_bit_le()
  • find_first_zero_bit_le()
  • test_bit_le()
  • set_bit_le()
    • __set_bit_le()
  • clear_bit_le()
    • __clear_bit_le()
  • test_and_set_bit_le()
    • __test_and_set_bit_le()
  • test_and_clear_bit_le()
    • __test_and_clear_bit_le()

 

etc

  • get_bitmask_order()
  • hweight_long()
  • sign_extend32()
  • sign_extend64()
  • get_count_order()
  • get_count_order_long()
  • __ffs64()
  • assign_bit()
    • __assign_bit()
  • set_mask_bits()
  • bit_clear_unless()

 

bitops 아키텍처별 헤더 파일

Bit operation은 기본 구현 헤더, Generic 라이브러리, asm-generic 헤더 및 아키텍처별 헤더에 구현되어 있다.
  • 기본 구현 헤더
    • include/linux/bitops.h
    • include/asm-generic/bitops.h
    • include/asm-generic/bitops/*.h
  • Generic 라이브러리
    • lib/find_bit.c
    • lib/hweight.c
  • 아키텍처별 헤더
    • arch/arm/include/asm/bitops.h
    • arch/arm64/include/asm/bitops.h

 


비트 검색 operations

fls()

include/asm-generic/bitops/builtin-fls.h

1/**
2 * fls - find last (most-significant) bit set
3 * @x: the word to search
4 *
5 * This is defined the same way as ffs.
6 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
7 */
1static __always_inline int fls(unsigned int x)
2{
3        return x ? sizeof(x) * 8 - __builtin_clz(x) : 0;
4}

unsigned int 타입 @x 값에서 셋 되어 있는 마지막(가장 좌측) 비트의 위치(1~32)를 리턴한다. 설정된 비트가 없으면 0을 리턴한다.

  • 예)
    • 0 -> 0
    • 0x0000_0001 -> 1
    • 0x0000_0011 -> 2
    • 0x8000_0000 -> 32
    • 0x8800_0000 -> 32

bitops-1

 

__fls()

include/asm-generic/bitops/builtin-_ffs.h

1/**
2 * __fls - find last (most-significant) set bit in a long word
3 * @word: the word to search
4 *
5 * Undefined if no set bit exists, so code should check against 0 first.
6 */
1static __always_inline unsigned long __fls(unsigned long word)
2{
3        return (sizeof(word) * 8) - 1 - __builtin_clzl(word);
4}

unsigned long 타입 @word에서 가장 마지막(가장 좌측) bit가 1인 bit 번호를 리턴한다. (based 0)

  • 예)
    • 0 -> 오류 (0 값이 입력으로 전달되면 안된다)
    • 0x0000_0001 -> 0
    • 0x0000_0011 -> 1
    • 0x8000_0000 -> 31
    • 0x8800_0000 -> 31
    • 0x8800_0000_0000_0000 -> 63 (64bits only)

 

ffs()

include/asm-generic/bitops/builtin-ffs.h

1/**
2 * ffs - find first bit set
3 * @x: the word to search
4 *
5 * This is defined the same way as
6 * the libc and compiler builtin ffs routines, therefore
7 * differs in spirit from the above ffz (man ffs).
8 */
1static __always_inline int ffs(int x)
2{
3        return __builtin_ffs(x);
4}

int 타입 @x에서 셋 되어 있는 첫(가장 우측) 비트의 위치(1~32)를 리턴한다. x 값이 0 즉, 설정된 비트가 없으면 0을 리턴한다.

  • 예)
    • 0 -> 0
    • 1 -> 1
    • 0x0000_0011 -> 1
    • 0x8000_0000 -> 32
    • 0x8800_0000 -> 31

bitops-3

 

__ffs()

include/asm-generic/bitops/builtin-_ffs.h

1/**
2 * __ffs - find first bit in word.
3 * @word: The word to search
4 *
5 * Undefined if no bit exists, so code should check against 0 first.
6 */
1static __always_inline unsigned long __ffs(unsigned long word)
2{
3        return __builtin_ctzl(word);
4}

unsigned long 타입 @word에서 셋 되어 있는 첫(가장 우측) 비트의 위치(0~31)를 리턴한다. x 값이 0 즉, 설정된 비트가 없으면 -1을 리턴한다.

  • 예)
    • 0 -> -1
    • 0x0000_0001 -> 0
    • 0x0000_0011 -> 1
    • 0x8000_0000 -> 31
    • 0x8800_0000 -> 30
    • 0x8800_0000_0000_0000 -> 62 (64bits only)

 

ffz()

include/asm-generic/bitops/ffz.h

1/*
2 * ffz - find first zero in word.
3 * @word: The word to search
4 *
5 * Undefined if no zero exists, so code should check against ~0UL first.
6 */
1#define ffz(x)  __ffs(~(x))

clear(0) 되어 있는 첫 비트의 위치(0~31)를 리턴한다.  x 값이 0xffff_ffff 즉,  zero bit가 없으면 -1을 리턴한다.

  • 예)
    • 0 -> 0
    • 0x0000_0001 -> 1
    • 0x0000_000f -> 4
    • 0x7fff_ffff -> 31
    • 0xffff_ffff -> -1

 

fls_long()

include/linux/bitops.h

1static inline unsigned fls_long(unsigned long l)
2{
3        if (sizeof(l) == 4)
4                return fls(l);
5        return fls64(l);
6}

long형 타입 인수 @l에 대해 lsb 부터 msb 로의 비트 검색을 하여 마지막 set bit를 알아오고 못 찾은 경우 0을 리턴한다. (based=1)

  • 예)
    • 0 -> 0
    • 1 -> 1
    • 0x8000_0000 -> 32
    • 0x8000_0000_0000_0000 -> 64 (64bits only)

 


Atomic 비트 조작 operations

다음 API들을 알아본다.

  • set_bit()
  • clear_bit()
  • change_bit()
  • test_and_set_bit()
  • test_and_clear_bit()
  • test_and_change_bit()

 

Atomic 비트 조작 – Generic (ARM64 포함)

ARM64 아키텍처는 atomic api를 사용하여 처리한다.

 

set_bit() – Generic (ARM64 포함)

include/asm-generic/bitops/atomic.h

1static inline void set_bit(unsigned int nr, volatile unsigned long *p)
2{
3        p += BIT_WORD(nr);
4        atomic_long_or(BIT_MASK(nr), (atomic_long_t *)p);
5}

unsigned long 타입 값(or 배열) @p에서 지정된 비트를 atomic 하게 1로 설정한다.

  • 예)
    • nr = 0 -> bit0 설정
    • nr = 1 -> bit1 설정
    • nr = 2 -> bit2 설정

 

clear_bit() – Generic (ARM64 포함)

include/asm-generic/bitops/atomic.h

1static inline void clear_bit(unsigned int nr, volatile unsigned long *p)
2{
3        p += BIT_WORD(nr);
4        atomic_long_andnot(BIT_MASK(nr), (atomic_long_t *)p);
5}

unsigned long 타입 값(or 배열) @p에서 지정된 비트를 atomic 하게 0으로 클리어한다.

  • 예)
    • nr = 0 -> bit0 클리어
    • nr = 1 -> bit1 클리어
    • nr = 2 -> bit2 클리어

 

change_bit() – Generic (ARM64 포함)

include/asm-generic/bitops/atomic.h

1static inline void change_bit(unsigned int nr, volatile unsigned long *p)
2{
3        p += BIT_WORD(nr);
4        atomic_long_xor(BIT_MASK(nr), (atomic_long_t *)p);
5}

unsigned long 타입 값(or 배열) @p에서 지정된 비트를 atomic 하게 뒤바꾼다(flip)

  • 예)
    • nr = 0 -> bit0 flip
    • nr = 1 -> bit1 flip
    • nr = 2 -> bit2 flip

 

test_and_set_bit() – Generic (ARM64 포함)

include/asm-generic/bitops/atomic.h

01static inline int test_and_set_bit(unsigned int nr, volatile unsigned long *p)
02{
03        long old;
04        unsigned long mask = BIT_MASK(nr);
05 
06        p += BIT_WORD(nr);
07        if (READ_ONCE(*p) & mask)
08                return 1;
09 
10        old = atomic_long_fetch_or(mask, (atomic_long_t *)p);
11        return !!(old & mask);
12}

unsigned long 타입 값(or 배열) @p에서 지정된 비트의 설정 여부를 0과 1로 알아오고, 결과와 상관 없이 해당 비트를 atomic 하게 1로 설정한다.

  • 예)
    • nr = 0 -> bit0 설정, 기존 읽은 old 값 반환
    • nr = 1 -> bit1 설정, 기존 읽은 old 값 반환
    • nr = 2 -> bit2 설정, 기존 읽은 old 값 반환

 

test_and_clear_bit() – Generic (ARM64 포함)

include/asm-generic/bitops/atomic.h

01static inline int test_and_clear_bit(unsigned int nr, volatile unsigned long *p)
02{
03        long old;
04        unsigned long mask = BIT_MASK(nr);
05 
06        p += BIT_WORD(nr);
07        if (!(READ_ONCE(*p) & mask))
08                return 0;
09 
10        old = atomic_long_fetch_andnot(mask, (atomic_long_t *)p);
11        return !!(old & mask);
12}

unsigned long 타입 값(or 배열) @p에서 지정된 비트의 설정 여부를 0과 1로 알아오고, 결과와 상관 없이 해당 비트를 atomic 하게 0으로 클리어한다.

  • 예)
    • nr = 0 -> bit0 클리어, 기존 읽은 old 값 반환
    • nr = 1 -> bit1 클리어, 기존 읽은 old 값 반환
    • nr = 2 -> bit2 클리어, 기존 읽은 old 값 반환

 

test_and_change_bit() – Generic (ARM64 포함)

include/asm-generic/bitops/atomic.h

1static inline int test_and_change_bit(unsigned int nr, volatile unsigned long *p)
2{
3        long old;
4        unsigned long mask = BIT_MASK(nr);
5 
6        p += BIT_WORD(nr);
7        old = atomic_long_fetch_xor(mask, (atomic_long_t *)p);
8        return !!(old & mask);
9}

unsigned long 타입 값(or 배열) @p에서 지정된 비트의 설정 여부를 0과 1로 알아오고, 결과와 상관 없이 해당 비트를 atomic 하게 뒤바꾼다(flip)

  • 예)
    • nr = 0 -> bit0 flip, 기존 읽은 old 값 반환
    • nr = 1 -> bit1 flip, 기존 읽은 old 값 반환
    • nr = 2 -> bit2 flip, 기존 읽은 old 값 반환

 


Atomic 비트 조작 – ARM32

set_bit()

arch/arm/include/asm/bitops.h

1#define set_bit(nr,p)                   ATOMIC_BITOP(set_bit,nr,p)

unsigned long 타입 값(or 배열) @p에서 지정된 비트를 atomic 하게 1로 설정한다.

 

clear_bit()

arch/arm/include/asm/bitops.h

1#define clear_bit(nr,p)                 ATOMIC_BITOP(clear_bit,nr,p)

unsigned long 타입 값(or 배열) @p에서 지정된 비트를 atomic 하게 0으로 클리어한다.

 

change_bit()

arch/arm/include/asm/bitops.h

1#define change_bit(nr,p)                ATOMIC_BITOP(change_bit,nr,p)

 

test_and_set_bit()

arch/arm/include/asm/bitops.h

1#define test_and_set_bit(nr,p)          ATOMIC_BITOP(test_and_set_bit,nr,p)

unsigned long 타입 값(or 배열) @p에서 지정된 비트의 설정 여부를 0과 1로 알아오고, 결과와 상관 없이 해당 비트를 atomic 하게 1로 설정한다.

 

test_and_clear_bit()

arch/arm/include/asm/bitops.h

1#define test_and_clear_bit(nr,p)        ATOMIC_BITOP(test_and_clear_bit,nr,p)

unsigned long 타입 값(or 배열) @p에서 지정된 비트의 설정 여부를 0과 1로 알아오고, 결과와 상관 없이 해당 비트를 atomic 하게 0으로 클리어한다.

 

test_and_change_bit()

arch/arm/include/asm/bitops.h

1#define test_and_change_bit(nr,p)       ATOMIC_BITOP(test_and_change_bit,nr,p)

unsigned long 타입 값(or 배열) @p에서 지정된 비트의 설정 여부를 0과 1로 알아오고, 결과와 상관 없이 해당 비트를 atomic 하게 뒤바꾼다(flip)

 

ATOMIC_BITOP()
1#ifndef CONFIG_SMP
2/*
3 * The __* form of bitops are non-atomic and may be reordered.
4 */
5#define ATOMIC_BITOP(name,nr,p)                 \
6        (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p))
7#else
8#define ATOMIC_BITOP(name,nr,p)         _##name(nr,p)
9#endif

SMP 시스템에서 nr 값의 상수 여부에 따라 다음 두 함수를 호출한다.

  • 예) set_bit()
    • 상수인 경우 __atomic_set_bit() 함수 호출
    • 변수인 경우 _set_bit() 함수 호출

 

____atomic_set_bit()

arch/arm/include/asm/bitops.h

01static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p)
02{
03        unsigned long flags;
04        unsigned long mask = BIT_MASK(bit);
05 
06        p += BIT_WORD(bit);
07 
08        raw_local_irq_save(flags);
09        *p |= mask;
10        raw_local_irq_restore(flags);
11}

 

____atomic_clear_bit()

arch/arm/include/asm/bitops.h

01static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
02{
03        unsigned long flags;
04        unsigned long mask = BIT_MASK(bit);
05 
06        p += BIT_WORD(bit);
07 
08        raw_local_irq_save(flags);
09        *p &= ~mask;
10        raw_local_irq_restore(flags);
11}

 

____atomic_change_bit()

arch/arm/include/asm/bitops.h

01static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
02{
03        unsigned long flags;
04        unsigned long mask = BIT_MASK(bit);
05 
06        p += BIT_WORD(bit);
07 
08        raw_local_irq_save(flags);
09        *p ^= mask;
10        raw_local_irq_restore(flags);
11}

 

____atomic_test_and_set_bit()

arch/arm/include/asm/bitops.h

01static inline int
02____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
03{
04        unsigned long flags;
05        unsigned int res;
06        unsigned long mask = BIT_MASK(bit);
07 
08        p += BIT_WORD(bit);
09 
10        raw_local_irq_save(flags);
11        res = *p;
12        *p = res | mask;
13        raw_local_irq_restore(flags);
14 
15        return (res & mask) != 0;
16}

 

____atomic_test_and_clear_bit()

arch/arm/include/asm/bitops.h

01static inline int
02____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
03{
04        unsigned long flags;
05        unsigned int res;
06        unsigned long mask = BIT_MASK(bit);
07 
08        p += BIT_WORD(bit);
09 
10        raw_local_irq_save(flags);
11        res = *p;
12        *p = res & ~mask;
13        raw_local_irq_restore(flags);
14 
15        return (res & mask) != 0;
16}

 

____atomic_test_and_change_bit()

arch/arm/include/asm/bitops.h

01static inline int
02____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
03{
04        unsigned long flags;
05        unsigned int res;
06        unsigned long mask = BIT_MASK(bit);
07 
08        p += BIT_WORD(bit);
09 
10        raw_local_irq_save(flags);
11        res = *p;
12        *p = res ^ mask;
13        raw_local_irq_restore(flags);
14 
15        return (res & mask) != 0;
16}

 

_set_bit()

arch/arm/lib/setbit.S

1bitop   _set_bit, orr

bitop 매크로를 사용하여 _set_bit에 대한 함수를 정의한다.

 

_clear_bit()

arch/arm/lib/clearbit.S

1bitop   _clear_bit, bic

bitop 매크로를 사용하여 _clear_bit에 대한 함수를 정의한다.

 

_chage_bit()

arch/arm/lib/changebit.S

1bitop   _change_bit, eor

bitop 매크로를 사용하여 _chage_bit에 대한 함수를 정의한다.

 

_test_and_set_bit()

arch/arm/lib/testsetbit.S

1testop  _test_and_set_bit, orreq, streq

bitop 매크로를 사용하여 _test_and_set_bit에 대한 함수를 정의한다.

 

_test_and_clear_bit()

arch/arm/lib/testclearbit.S

1testop  _test_and_clear_bit, bicne, strne

bitop 매크로를 사용하여 _test_and_clear_bit에 대한 함수를 정의한다.

 

_test_and_change_bit()

arch/arm/lib/testchangebit.S

1testop  _test_and_change_bit, eor, str

bitop 매크로를 사용하여 _test_and_change_bit에 대한 함수를 정의한다.

 

bitop 매크로

arch/arm/lib/bitops.h

01#if __LINUX_ARM_ARCH__ >= 6
02        .macro  bitop, name, instr
03ENTRY(  \name           )
04UNWIND( .fnstart        )
05        ands    ip, r1, #3
06        strneb  r1, [ip]                @ assert word-aligned
07        mov     r2, #1
08        and     r3, r0, #31             @ Get bit offset
09        mov     r0, r0, lsr #5
10        add     r1, r1, r0, lsl #2      @ Get word offset
11#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
12        .arch_extension mp
13        ALT_SMP(W(pldw) [r1])
14        ALT_UP(W(nop))
15#endif
16        mov     r3, r2, lsl r3
171:      ldrex   r2, [r1]
18        \instr  r2, r2, r3
19        strex   r0, r2, [r1]
20        cmp     r0, #0
21        bne     1b
22        bx      lr
23UNWIND( .fnend          )
24ENDPROC(\name           )
25        .endm

 


Atomic 비트 검색 operations

다음 함수들을 알아본다.

  • find_next_bit()
  • find_next_zero_bit()
  • find_next_and_bit()
  • find_first_bit()
  • find_first_zero_bit()
  • find_last_bit()

 

비트 검색 – Generic (ARM64 포함)

 

find_next_bit()

include/asm-generic/bitops/find.h

1/**
2 * find_next_bit - find the next set bit in a memory region
3 * @addr: The address to base the search on
4 * @offset: The bitnumber to start searching at
5 * @size: The bitmap size in bits
6 *
7 * Returns the bit number for the next set bit
8 * If no bits are set, returns @size.
9 */

 

lib/find_bit.c

1/*
2 * Find the next set bit in a memory region.
3 */
1unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
2                            unsigned long offset)
3{
4        return _find_next_bit(addr, NULL, size, offset, 0UL, 0);
5}
6EXPORT_SYMBOL(find_next_bit);

@addr 비트맵의 @size 제한 범위내에서 @offset 비트를 포함하여 비트가 1로 설정된 비트 위치를 찾아 알아온다. 발견하지 못한 경우는 size 값을 반환한다. (based 0)

  • 예)
    • addr=0xffff_8003, size=16, offset=-1 -> 16
    • addr=0xffff_8003, size=16, offset=0 -> 0
    • addr=0xffff_8003, size=16, offset=1 -> 1
    • addr=0xffff_8003, size=16, offset=2 -> 15
    • addr=0xffff_8003, size=16, offset=14 -> 15
    • addr=0xffff_8003, size=16, offset=15 -> 15
    • addr=0xffff_8003, size=16, offset=16 -> 16

 

다음 그림은 find_next_bit()에서 검색하는 비트들을 하늘색으로 표시하였다.

 

find_next_zero_bit()

include/asm-generic/bitops/find.h

1/**
2 * find_next_zero_bit - find the next cleared bit in a memory region
3 * @addr: The address to base the search on
4 * @offset: The bitnumber to start searching at
5 * @size: The bitmap size in bits
6 *
7 * Returns the bit number of the next zero bit
8 * If no bits are zero, returns @size.
9 */

 

lib/find_bit.c

1unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
2                                 unsigned long offset)
3{
4        return _find_next_bit(addr, NULL, size, offset, ~0UL, 0);
5}
6EXPORT_SYMBOL(find_next_zero_bit);

@addr 비트맵의 @size 제한 범위내에서 @offset 비트를 포함하여 비트가 0으로 클리어된 비트 위치를 찾아 알아온다. 발견하지 못한 경우는 size 값을 반환한다.  (based 0)

  • 예)
    • addr=0xffff_800a, size=16, offset=-1 -> 16
    • addr=0xffff_800a, size=16, offset=0 -> 0
    • addr=0xffff_800a, size=16, offset=1 -> 2
    • addr=0xffff_800a, size=16, offset=2 -> 2
    • addr=0xffff_800a, size=16, offset=3 -> 4
    • addr=0xffff_800a, size=16, offset=14 -> 14
    • addr=0xffff_800a, size=16, offset=15 -> 16
    • addr=0xffff_800a, size=16, offset=16 -> 16

 

다음 그림은 find_next_zero_bit()에서 검색하는 비트들을 하늘색으로 표시하였다.

 

find_next_and_bit()

include/asm-generic/bitops/find.h

01/**
02 * find_next_and_bit - find the next set bit in both memory regions
03 * @addr1: The first address to base the search on
04 * @addr2: The second address to base the search on
05 * @offset: The bitnumber to start searching at
06 * @size: The bitmap size in bits
07 *
08 * Returns the bit number for the next set bit
09 * If no bits are set, returns @size.
10 */

 

lib/find_bit.c

1unsigned long find_next_and_bit(const unsigned long *addr1,
2                const unsigned long *addr2, unsigned long size,
3                unsigned long offset)
4{
5        return _find_next_bit(addr1, addr2, size, offset, 0UL, 0);
6}
7EXPORT_SYMBOL(find_next_and_bit);

@addr과 @addr2 두 비트맵에서 @size 제한 범위내에서 @offset 비트를 포함하여 비트가 둘 다 1로 설정된 비트 위치를 찾아 알아온다. 발견하지 못한 경우는 size 값을 반환한다. (based 0)

  • 예)
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=-1 -> 16
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=0 -> 1
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=1 -> 1
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=2 -> 3
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=3 -> 3
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=4 -> 15
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=14 -> 15
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=15 -> 15
    • addr1=0xffff_800a, addr2=0xffff_800f, size=16, offset=16 -> 16

 

다음 그림은 find_next_and_bit()에서 검색하는 비트들을 하늘색으로 표시하였다.

 

_find_next_bit()

lib/find_bit.c

1/*
2 * This is a common helper function for find_next_bit, find_next_zero_bit, and
3 * find_next_and_bit. The differences are:
4 *  - The "invert" argument, which is XORed with each fetched word before
5 *    searching it for one bits.
6 *  - The optional "addr2", which is anded with "addr1" if present.
7 */
01static unsigned long _find_next_bit(const unsigned long *addr1,
02                const unsigned long *addr2, unsigned long nbits,
03                unsigned long start, unsigned long invert, unsigned long le)
04{
05        unsigned long tmp, mask;
06 
07        if (unlikely(start >= nbits))
08                return nbits;
09 
10        tmp = addr1[start / BITS_PER_LONG];
11        if (addr2)
12                tmp &= addr2[start / BITS_PER_LONG];
13        tmp ^= invert;
14 
15        /* Handle 1st word. */
16        mask = BITMAP_FIRST_WORD_MASK(start);
17        if (le)
18                mask = swab(mask);
19 
20        tmp &= mask;
21 
22        start = round_down(start, BITS_PER_LONG);
23 
24        while (!tmp) {
25                start += BITS_PER_LONG;
26                if (start >= nbits)
27                        return nbits;
28 
29                tmp = addr1[start / BITS_PER_LONG];
30                if (addr2)
31                        tmp &= addr2[start / BITS_PER_LONG];
32                tmp ^= invert;
33        }
34 
35        if (le)
36                tmp = swab(tmp);
37 
38        return min(start + __ffs(tmp), nbits);
39}

이 함수는 find_next_bit(), find_next_zero_bit() 및 find_next_and_bit() 함수에서 사용되는 헬퍼 함수이다.

  • 코드 라인 7~8에서 시작 위치 @start가 @nbits 이상인 경우 에러 의미를 갖는 @nbits를 반환한다.
  • 코드 라인 10~13에서 비트맵 @addr1에서 @start에 해당하는 unsigned long 만큼을 알아온다. 만일 비트맵 @addr2가 지정된 경우 동일하게 @start 에 해당하는 unsigned long 만큼을 알아온 후 먼저 알아온 값과 and 연산을 수행한다. 마지막으로 @invert 값과 exclusive or 연산을 수행하여 tmp에 대입한다.
  • 코드 라인 20~24에서 tmp 값에서 @start 비트 미만의 모든 비트를 모두 0으로 클리어하여 처리하지 않도록 한다.
    • 예) tmp=3, @start=1
      • tmp=2 (bit1 미만의 bit0만 클리어하였다.)
    • 만일 리틀 엔디안 @le가 설정된 경우라면 tmp 값을 swap 한다.
      • 예) tmp=0x1122_3344_5566_7788, le=1
        • tmp=0x8877_6655_4433_2211
  • 코드 라인 26에서 @start 값을 BITS_PER_LONG 단위로 절삭한다.
  • 코드 라인 28~37에서 만일 tmp 값이 0인 경우 다음 unsigned long 값을 알아온다. 물론 start가 @nbits 이상인 경우 에러 의미를 갖는 @nbits를 반환한다.
  • 코드 라인 39~40에서 만일 리틀 엔디안 @le가 설정된 경우라면 tmp 값을 원래 값을 갖기 위해 swap 한다.
  • 코드 라인 42에서 tmp에서 1로 설정된 가장 첫(가장 우측) 비트의 위치를 반환한다.

 

find_first_zero_bit() – Generic (ARM64 포함)

lib/find_bit.c

1/*
2 * Find the first cleared bit in a memory region.
3 */
01unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
02{
03        unsigned long idx;
04 
05        for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
06                if (addr[idx] != ~0UL)
07                        return min(idx * BITS_PER_LONG + ffz(addr[idx]), size);
08        }
09 
10        return size;
11}
12EXPORT_SYMBOL(find_first_zero_bit);

@addr 비트맵의 @size 제한 범위내에서 비트가 0으로 클리어된 가장 처음 비트 위치를 찾아 알아온다. 발견하지 못한 경우는 size 값을 반환한다. (based 0)

  • 예) addr=0xffff_800a, size=16 -> 0

 

다음 그림은 find_first_zero_bit()에서 검색한 첫 번째 비트를 하늘색으로 표시하였다.

 

find_first_bit() – Generic (ARM64 포함)

lib/find_bit.c

1/*
2 * Find the first set bit in a memory region.
3 */
01unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
02{
03        unsigned long idx;
04 
05        for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
06                if (addr[idx])
07                        return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
08        }
09 
10        return size;
11}
12EXPORT_SYMBOL(find_first_bit);

@addr 비트맵의 @size 제한 범위내에서 비트가 1로 설정된 가장 처음(가장 우측) 비트 위치를 찾아 알아온다. 발견하지 못한 경우는 size 값을 반환한다. (based 0)

  • 예) addr=0xffff_800a, size=16 -> 1

 

다음 그림은 find_first_bit()에서 검색한 첫 번째 비트를 하늘색으로 표시하였다.

 

find_last_bit() – Generic (ARM, ARM64 포함)

lib/find_bit.c

01unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
02{
03        if (size) {
04                unsigned long val = BITMAP_LAST_WORD_MASK(size);
05                unsigned long idx = (size-1) / BITS_PER_LONG;
06 
07                do {
08                        val &= addr[idx];
09                        if (val)
10                                return idx * BITS_PER_LONG + __fls(val);
11 
12                        val = ~0ul;
13                } while (idx--);
14        }
15        return size;
16}
17EXPORT_SYMBOL(find_last_bit);

@addr 비트맵의 @size 제한 범위내에서 비트가 1로 설정된 가장 마지막(가장 좌측) 비트 위치를 찾아 알아온다. 발견하지 못한 경우는 size 값을 반환한다.

  • 예) addr=0xffff_800a, size=16 -> 15

 

다음 그림은 find_last_bit()에서 검색한 첫 번째 비트를 하늘색으로 표시하였다.

 


비트 검색 – ARM32

find_first_zero_bit()

arch/arm/include/asm/bitops.h

1#ifndef __ARMEB__
2#define find_first_zero_bit(p,sz)       _find_first_zero_bit_le(p,sz)
3#else
4#define find_first_zero_bit(p,sz)       _find_first_zero_bit_be(p,sz)
5#endif

비트맵의 size 제한 범위내에서 첫 번째 zero 비트 위치를 반환한다. 발견하지 못한 경우는 size 값을 반환한다. (based 0)

  • fls()가 find_first_zero_bit()와 세 가지 다른 점
    • 처리되는 데이터 타입이 다르다.
      • fls()는 unsigned int 타입에서 동작한다.
      • find_last_zero_bit()는 비트 제한이 없는 비트맵에서 동작한다.
    • 검색 비트 종류(set(1) bit / clear(0))
      • fls()는 set(1) bit를 검색한다.
      • find_first_zero_bit는 clear(0) bit를 검색한다.
    • 리턴되는 포지션 값
      • fls()는 bit0을 검색하면 1로 리턴한다. 검색되지 않으면 0을 리턴한다.
      • find_last_zero_bit는 bit0을 검색하면 0으로 리턴한다. 검색되지 않으면 max_bits 값을 리턴한다.
  • 이 매크로는 엔디안에 따라 구현 루틴이 다르다.

 

bits0, bit1, bit32들이 모두 1인 64개의 비트마스크를 예로알아본다.

  • 논리적 비트마스크 (first zero bit=2)
    • 0x0000_0001_0000_0003 = 0b00000000_00000000_00000000_00000001_00000000_00000000_00000000_00000011
  • 리틀 엔디안으로 저장 시:
    • {0x03, 0x00, 00, 00, 01, 00, 00, 00}
    • 32비트 레지스터에 2번에 나누어 읽어들이면
      • 0x0000_0003
      • 0x0000_0001
  • 빅 엔디안으로 저장 시:
    • {0x00, 00, 00, 01, 00, 00, 00, 03}
    • 32비트 레지스터에 2번에 나누어 읽어들이면
      • 0x0000_0001
      • 0x0000_0003

 

한 번 더 알아보면,

  • 논리적 비트마스크 (first zero bit=8)
    • 0xff12_3456_78ff = 0b11111111_00010010_00110100_01010110_01111000_11111111
  • 리틀 엔디안으로 저장 시:
    • { 0xff, 0x78, 0x56, 0x34, 0x12, 0xff }
    • 32비트 레지스터에 2번에 나누어 읽어들이면
      • 0x3456_78ff
      • 0x0000_ff12
  • 빅 엔디안으로 저장 시:
    • {0xff, 0x12, 0x34, 0x56, 0x78, 0xff }
    • 32비트 레지스터에 2번에 나누어 읽어들이면
      • 0xff12_3456
      • 0x78ff_0000

 

bitops-4a

 

_find_first_zero_bit_le()

arch/arm/lib/findbit.S

1/*
2 * Purpose  : Find a 'zero' bit
3 * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit);
4 */
01ENTRY(_find_first_zero_bit_le)
02                teq     r1, #0 
03                beq     3f
04                mov     r2, #0
051:
06 ARM(           ldrb    r3, [r0, r2, lsr #3]    )
07 THUMB(         lsr     r3, r2, #3              )
08 THUMB(         ldrb    r3, [r0, r3]            )
09                eors    r3, r3, #0xff           @ invert bits
10                bne     .L_found                @ any now set - found zero bit
11                add     r2, r2, #8              @ next bit pointer
122:              cmp     r2, r1                  @ any more?
13                blo     1b
143:              mov     r0, r1                  @ no free bits
15                ret     lr
16ENDPROC(_find_first_zero_bit_le)
  • 레지스터 용도
    • r0(addr): 비트맵이 위치한 주소
    • r1(maxbit): maxbit로 처리할 최대 비트 수
    • r0(결과): clear(0) bit를 찾은 비트 번호를 리턴
      • 0~n: 첫 번째 비트가 clear bit.
      • maxbit: 비트맵 범위내에서 찾지 못함(not found).
    • r2(currbit): 현재 검색하고 있는 비트
      • 다음 바이트를 검색할 때마다 8비트씩 증가
    • r3(8bit 비트맵): 읽어들인 1바이트(8비트) 비트맵
  • 비트맵에서 1 바이트(8비트) 단위로 읽어와서 clear(0) 비트가 있는지 검사하여 있으면 .L_found 레이블로 이동한다.
  • teq     r1, #0
    • 처리할 비트가 없으며(maxbit가 0이면) r0←0(error)를 리턴
  • mov      r2, #0
    • currbit를 0으로 대입(처음 시작 비트)
  • 1: ldrb    r3, [r0, r2, lsr #3]
    • r3에 비트맵 주소 + currbit / 8을 하여 1바이트를 읽어온다.
  • eors    r3, r3, #0xff
    • 읽어들인 데이터를 반전(invert) 시킨다.
  • bne     .L_found
    • 즉, 읽어들인 8비트 비트맵에 clear(bit)가 존재하면 .L_found로 이동
  • add     r3, r3, #8
    • currbit += 8
      • 다음 바이트로 이동
  • cmp r2, r1
    • 아직 끝나지 않았으면(curbit < maxbit) 1b로 이동
  • #3: mov r0, r1
    • r0 ← r1(maxbit) 값을 리턴(not found)
1/*
2 * One or more bits in the LSB of r3 are assumed to be set.
3 */
01.L_found:
02                rsb     r0, r3, #0
03                and     r3, r3, r0
04                clz     r3, r3
05                rsb     r3, r3, #31
06                add     r0, r2, r3
07 
08                cmp     r1, r0                  @ Clamp to maxbit
09                movlo   r0, r1
10                ret     lr
  • rsb     r0, r3, #0
    • r0 = -r3
  • and     r3, r3, r0
    • r3 &= r0
    • 위의 rsb, and 명령은 r3 &= -r3와 동일한 연산이고 이렇게 하면 set(bit)가 lsb 쪽에 하나만 남게된다.

bitops-5

  • clz     r3, r3
    • 시작 비트만 남겨놨으니 그 앞쪽에 있는 0 bit를 카운트한다.
    • counter leading zero로 bit31부터 시작해서 set(1) bit가 발견되기 전까지의 clear(0) bit 수를 카운트 한다.
      • clz(0x90) -> 24
      • clz(0x7777_7777) -> 1
  • rsb     r3, r3, #31
    • 31 – r3(0 비트 갯수)
  • add     r0, r2, r3
    • r0 ← r2(curbit) + r3(바이트 내에서 찾은 위치)
  • movlo   r0, r1
    • 범위를 벗어난 위치에서 비트가 발견되면r0 ← maxbit(not found)를 리턴
    • r1(maxbit> < r0(찾은 위치)

 

find_first_bit() – ARM

arch/arm/include/asm/bitops.h

1#define find_first_bit(p,sz)            _find_first_bit_le(p,sz)

비트맵의 size 범위내에서 set(1) 비트가 처음 발견되는 비트 번호를 알아온다. 발견하지 못한 경우 size를 반환한다. (based 0)

  • 구현은 엔디안에 따라 두 개로 나뉘어 있다.
  • 예) *addr[]=0x8800_0000_0000_0000, size=64
    • -> 59
  • 예) *addr[]=0x0000_0088, size=32
    • -> 3

 

1/*
2 * Purpose  : Find a 'one' bit
3 * Prototype: int find_first_bit(const unsigned long *addr, unsigned int maxbit);
4 */
01ENTRY(_find_first_bit_le)
02                teq     r1, #0 
03                beq     3f
04                mov     r2, #0
051:
06 ARM(           ldrb    r3, [r0, r2, lsr #3]    )
07 THUMB(         lsr     r3, r2, #3              )
08 THUMB(         ldrb    r3, [r0, r3]            )
09                movs    r3, r3
10                bne     .L_found                @ any now set - found zero bit
11                add     r2, r2, #8              @ next bit pointer
122:              cmp     r2, r1                  @ any more?
13                blo     1b
143:              mov     r0, r1                  @ no free bits
15                ret     lr
16ENDPROC(_find_first_bit_le)
  • 레지스터 용도
    • r0(addr): 비트맵이 위치한 주소
    • r1(maxbit): maxbit로 처리할 최대 비트 수
    • r0(결과): clear(0) bit를 찾은 비트 번호를 리턴
      • 0~n: set bit가 발견된 비트 위치.
      • maxbit: 비트맵 범위내에서 찾지 못함(not found).
    • r2(currbit): 현재 검색하고 있는 비트(0, 8, 16, 24, …)
      • 다음 바이트를 검색할 때마다 8비트씩 증가
    • r3(8bit 비트맵): 읽어들인 1바이트(8비트) 비트맵

비트맵에서 1 바이트(8비트) 단위로 읽어와서 clear(0) 비트가 있는지 검사하여 있으면 .L_found 레이블로 이동한다.

  • teq     r1, #0
    • 처리할 비트가 없으며(maxbit가 0이면) r0←0(error)를 리턴
  • mov      r2, #0
    • currbit를 0으로 대입(처음 시작 비트)
  • 1: ldrb    r3, [r0, r2, lsr #3]
    • r3에 비트맵 주소 + currbit / 8을 하여 1바이트를 읽어온다.
  • bne     .L_found
    • 즉, 읽어들인 8비트 비트맵에 set bit가 존재하면 .L_found로 이동
  • add     r3, r3, #8
    • currbit += 8
      • 다음 바이트로 이동
  • cmp r2, r1
    • 아직 끝나지 않았으면(curbit < maxbit) 1b로 이동
  • 3: mov r0, r1
    • r0 ← r1(maxbit) 값을 리턴(not found)
  • .L_found는 _find_first_zero_bit_le()에서 사용한 루틴과 동일하다.
  • 예) byte *addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88}, size=64
    • -> 59
  • 예) byte *addr[] = {0x11, 0x00, 0x00, 0x00}, size=32
    • -> 0

 


hweight operations

hweight_long()

include/linux/bitops.h

1static inline unsigned long hweight_long(unsigned long w)
2{
3        return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
4}

long 타입 w에 대해 1로 설정되어 있는 bit 수를 리턴한다.

 

hweight**()

include/asm-generic/bitops/const_hweight.h

1/*
2 * Generic interface.
3 */
1#define hweight8(w) (__builtin_constant_p(w) ? __const_hweight8(w) : __arch_hweight8(w))
2#define hweight16(w) (__builtin_constant_p(w) ? __const_hweight16(w) : __arch_hweight16(w))
3#define hweight32(w) (__builtin_constant_p(w) ? __const_hweight32(w) : __arch_hweight32(w))
4#define hweight64(w) (__builtin_constant_p(w) ? __const_hweight64(w) : __arch_hweight64(w))

1로 설정되어 있는 bit 수를 리턴한다.

 

__const_hweight**()

include/asm-generic/bitops/const_hweight.h

1/*
2 * Compile time versions of __arch_hweightN()
3 */
01#define __const_hweight8(w)             \
02        ((unsigned int)                 \
03         ((!!((w) & (1ULL << 0))) +     \
04          (!!((w) & (1ULL << 1))) +     \
05          (!!((w) & (1ULL << 2))) +     \
06          (!!((w) & (1ULL << 3))) +     \
07          (!!((w) & (1ULL << 4))) +     \
08          (!!((w) & (1ULL << 5))) +     \
09          (!!((w) & (1ULL << 6))) +     \
10          (!!((w) & (1ULL << 7)))))
11  
12#define __const_hweight16(w) (__const_hweight8(w)  + __const_hweight8((w)  >> 8 ))
13#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16))
14#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32))

1로 설정되어 있는 bit 수를 리턴한다.

 

__arch_hweight**()

include/asm-generic/bitops/arch_hweight.h

01static inline unsigned int __arch_hweight32(unsigned int w)
02{
03        return __sw_hweight32(w);
04}
05 
06static inline unsigned int __arch_hweight16(unsigned int w)
07{
08        return __sw_hweight16(w);
09}
10 
11static inline unsigned int __arch_hweight8(unsigned int w)
12{
13        return __sw_hweight8(w);
14}
15 
16static inline unsigned long __arch_hweight64(__u64 w)
17{
18        return __sw_hweight64(w);
19}

 

__sw_hweight32()

lib/hweight.c

1/**
2 * hweightN - returns the hamming weight of a N-bit word
3 * @x: the word to weigh
4 *
5 * The Hamming Weight of a number is the total number of bits set in it.
6 */
01unsigned int __sw_hweight32(unsigned int w)
02{      
03#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER
04        w -= (w >> 1) & 0x55555555;
05        w =  (w & 0x33333333) + ((w >> 2) & 0x33333333);
06        w =  (w + (w >> 4)) & 0x0f0f0f0f;
07        return (w * 0x01010101) >> 24;
08#else
09        unsigned int res = w - ((w >> 1) & 0x55555555);
10        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
11        res = (res + (res >> 4)) & 0x0F0F0F0F;
12        res = res + (res >> 8);
13        return (res + (res >> 16)) & 0x000000FF;
14#endif
15}
16EXPORT_SYMBOL(__sw_hweight32);

 

__sw_hweight16()

lib/hweight.c

1unsigned int __sw_hweight16(unsigned int w)
2{
3        unsigned int res = w - ((w >> 1) & 0x5555);
4        res = (res & 0x3333) + ((res >> 2) & 0x3333);
5        res = (res + (res >> 4)) & 0x0F0F;
6        return (res + (res >> 8)) & 0x00FF;
7}
8EXPORT_SYMBOL(__sw_hweight16);

 

__sw_hweight8()

lib/hweight.c

1unsigned int __sw_hweight8(unsigned int w)
2{
3        unsigned int res = w - ((w >> 1) & 0x55);
4        res = (res & 0x33) + ((res >> 2) & 0x33);
5        return (res + (res >> 4)) & 0x0F;
6}
7EXPORT_SYMBOL(__sw_hweight8);

 

__sw_hweight64()

lib/hweight.c

01unsigned long __sw_hweight64(__u64 w)
02{
03#if BITS_PER_LONG == 32
04        return __sw_hweight32((unsigned int)(w >> 32)) +
05               __sw_hweight32((unsigned int)w);
06#elif BITS_PER_LONG == 64
07#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER
08        w -= (w >> 1) & 0x5555555555555555ul;
09        w =  (w & 0x3333333333333333ul) + ((w >> 2) & 0x3333333333333333ul);
10        w =  (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0ful;
11        return (w * 0x0101010101010101ul) >> 56;
12#else
13        __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
14        res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
15        res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
16        res = res + (res >> 8);
17        res = res + (res >> 16);
18        return (res + (res >> 32)) & 0x00000000000000FFul;
19#endif
20#endif
21}
22EXPORT_SYMBOL(__sw_hweight64);

 

참고

댓글 남기기