1
linux/lib
Akinobu Mita f9b4192923 [PATCH] bitops: hweight() speedup
<linux@horizon.com> wrote:

This is an extremely well-known technique.  You can see a similar version that
uses a multiply for the last few steps at
http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel whch
refers to "Software Optimization Guide for AMD Athlon 64 and Opteron
Processors"
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25112.PDF

It's section 8.6, "Efficient Implementation of Population-Count Function in
32-bit Mode", pages 179-180.

It uses the name that I am more familiar with, "popcount" (population count),
although "Hamming weight" also makes sense.

Anyway, the proof of correctness proceeds as follows:

	b = a - ((a >> 1) & 0x55555555);
	c = (b & 0x33333333) + ((b >> 2) & 0x33333333);
	d = (c + (c >> 4)) & 0x0f0f0f0f;
#if SLOW_MULTIPLY
	e = d + (d >> 8)
	f = e + (e >> 16);
	return f & 63;
#else
	/* Useful if multiply takes at most 4 cycles */
	return (d * 0x01010101) >> 24;
#endif

The input value a can be thought of as 32 1-bit fields each holding their own
hamming weight.  Now look at it as 16 2-bit fields.  Each 2-bit field a1..a0
has the value 2*a1 + a0.  This can be converted into the hamming weight of the
2-bit field a1+a0 by subtracting a1.

That's what the (a >> 1) & mask subtraction does.  Since there can be no
borrows, you can just do it all at once.

Enumerating the 4 possible cases:

0b00 = 0  ->  0 - 0 = 0
0b01 = 1  ->  1 - 0 = 1
0b10 = 2  ->  2 - 1 = 1
0b11 = 3  ->  3 - 1 = 2

The next step consists of breaking up b (made of 16 2-bir fields) into
even and odd halves and adding them into 4-bit fields.  Since the largest
possible sum is 2+2 = 4, which will not fit into a 4-bit field, the 2-bit
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                          "which will not fit into a 2-bit field"

fields have to be masked before they are added.

After this point, the masking can be delayed.  Each 4-bit field holds a
population count from 0..4, taking at most 3 bits.  These numbers can be added
without overflowing a 4-bit field, so we can compute c + (c >> 4), and only
then mask off the unwanted bits.

This produces d, a number of 4 8-bit fields, each in the range 0..8.  From
this point, we can shift and add d multiple times without overflowing an 8-bit
field, and only do a final mask at the end.

The number to mask with has to be at least 63 (so that 32 on't be truncated),
but can also be 128 or 255.  The x86 has a special encoding for signed
immediate byte values -128..127, so the value of 255 is slower.  On other
processors, a special "sign extend byte" instruction might be faster.

On a processor with fast integer multiplies (Athlon but not P4), you can
reduce the final few serially dependent instructions to a single integer
multiply.  Consider d to be 3 8-bit values d3, d2, d1 and d0, each in the
range 0..8.  The multiply forms the partial products:

	           d3 d2 d1 d0
	        d3 d2 d1 d0
	     d3 d2 d1 d0
	+ d3 d2 d1 d0
	----------------------
	           e3 e2 e1 e0

Where e3 = d3 + d2 + d1 + d0.   e2, e1 and e0 obviously cannot generate
any carries.

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-26 08:59:30 -08:00
..
reed_solomon [PATCH] sem2mutex: kernel/ 2006-03-23 07:38:10 -08:00
zlib_deflate [PATCH] lib/zlib*: cleanups 2006-01-10 08:01:57 -08:00
zlib_inflate [PATCH] lib/zlib*: cleanups 2006-01-10 08:01:57 -08:00
.gitignore Add some basic .gitignore files 2005-10-18 08:26:15 -07:00
bitmap.c [PATCH] bitops: hweight() related cleanup 2006-03-26 08:57:15 -08:00
bust_spinlocks.c
cmdline.c
cpumask.c [PATCH] cpumask: uninline any_online_cpu() 2006-03-25 08:23:00 -08:00
crc16.c [PATCH] lib/crc16: added crc16 algorithm. 2005-09-08 14:41:27 -07:00
crc32.c
crc32defs.h
crc-ccitt.c
ctype.c
dec_and_lock.c [PATCH] atomic: dec_and_lock use atomic primitives 2006-01-08 20:13:48 -08:00
div64.c
dump_stack.c
errno.c
extable.c [PATCH] powerpc: trivial: modify comments to refer to new location of files 2006-02-10 16:53:51 +11:00
find_next_bit.c [PATCH] bitops: generic ext2_{set,clear,test,find_first_zero,find_next_zero}_bit() 2006-03-26 08:57:11 -08:00
gen_crc32table.c
genalloc.c [PATCH] fix broken lib/genalloc.c 2005-11-28 14:42:23 -08:00
halfmd4.c
hweight.c [PATCH] bitops: hweight() speedup 2006-03-26 08:59:30 -08:00
idr.c [PATCH] Whitespace and CodingStyle cleanup for lib/idr.c 2005-10-30 17:37:19 -08:00
inflate.c
int_sqrt.c [PATCH] lib: Fix bug in int_sqrt() for 64 bit longs 2006-02-03 08:32:08 -08:00
iomap_copy.c [PATCH] iomap_copy fallout (m68k) 2006-02-18 16:30:40 -05:00
iomap.c
Kconfig [PATCH] lib/crc16: added crc16 algorithm. 2005-09-08 14:41:27 -07:00
Kconfig.debug [PATCH] x86_64: Don't enable CONFIG_UNWIND_INFO by default for DEBUG_KERNEL 2006-03-25 09:14:39 -08:00
kernel_lock.c [PATCH] spinlock consolidation 2005-09-10 10:06:21 -07:00
klist.c [PATCH] klist: Fix broken kref counting in find functions 2006-01-04 16:18:08 -08:00
kobject_uevent.c [PATCH] kobject: fix build error if CONFIG_SYSFS=n 2006-03-20 13:42:57 -08:00
kobject.c [PATCH] kobject_add_dir 2006-03-20 13:42:59 -08:00
kref.c [PATCH] kref: avoid an atomic operation in kref_put() 2006-03-20 13:42:57 -08:00
libcrc32c.c
Makefile [PATCH] bitops: generic hweight{64,32,16,8}() 2006-03-26 08:57:11 -08:00
parser.c
prio_tree.c
radix-tree.c [PATCH] radix-tree documentation cleanups 2006-03-25 08:22:59 -08:00
rbtree.c
rwsem-spinlock.c
rwsem.c
semaphore-sleepers.c
sha1.c
smp_processor_id.c [PATCH] fix missing includes 2005-10-30 17:37:32 -08:00
sort.c [PATCH] fix missing includes 2005-10-30 17:37:32 -08:00
spinlock_debug.c [PATCH] Fix spinlock debugging delays to not time out too early 2006-02-07 16:12:33 -08:00
string.c [PATCH] multiple exports of strpbrk 2006-03-22 07:53:56 -08:00
swiotlb.c BUG_ON() Conversion in lib/swiotlb.c 2006-03-24 18:47:11 +01:00
textsearch.c [PATCH] gfp_t: lib/* 2005-10-28 08:16:47 -07:00
ts_bm.c [TEXTSEARCH]: Fix broken good shift array calculation in Boyer-Moore 2006-02-02 17:15:41 -08:00
ts_fsm.c [PATCH] gfp flags annotations - part 1 2005-10-08 15:00:57 -07:00
ts_kmp.c [PATCH] gfp flags annotations - part 1 2005-10-08 15:00:57 -07:00
vsprintf.c [PATCH] fix missing includes 2005-10-30 17:37:32 -08:00