Skip to contentSkip to conversation

Faster generic_fls

RFC PATCH [email protected] 1 participant 1 message May 1, 2003

lore
Share & tools
lore
#0 lore raw

The Fount of Holy Pengun Pee expressed himself thus:

Quoted 13 lines

Yeah, except if you want best code generation you should probably use

	static inline int fls(int x)
	{
		int bit;
		/* Only well-defined for non-zero */
		asm("bsrl %1,%0":"=r" (bit):"rm" (x));
		return x ? bit : 32;
	}

which should generate (assuming you give "-march=xxxx" to tell gcc to use cmov):

Quoted 6 lines

movl $32, %eax
bsrl %edx,%ecx
testl %edx, %edx
cmovne %ecx, %eax

which looks pretty optimal.

Except that the testl is unnecessary. The full semantics of bsrl are:

if (source != 0) {
	destination = <index of most significant set bit in source>;
	ZF = 0;
} else {
	destination = UNDEFINED;
	ZF = 1;
}

Thus, there are two reasonable code sequences:

asm(" bsrl %2, %1"
"\n cmovne %1, %0" : "=r" (bit), "=r" (temp) : "rm" (x), "0" (32));

and (if I've got the earlyclobber syntax right):

asm(" bsrl %1, %0"
"\n cmoveq %2, %0" : "=&r,&r" (bit) : "0,rm" (x), "rm,rm" (32));

Note that in this latter case, I have to list %1 == %0 as an explicit alternative, because otherwise the & on operand 0 would tell GCC to forbid that combination and it's only %0 == %2 that's forbidden.

(The first alternative is listed first because it uses fewer registers and so is preferred, all other things being equal.)

Unfortunately, I'm not sure how to let GCC choose between these two alternatives...