mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
x86/bitops: Improve arch_ffs() in the general case
The asm in arch_ffs() is safe but inefficient. CMOV would be an improvement over a conditional branch, but for 64bit CPUs both Intel and AMD have provided enough details about the behaviour for a zero input. It is safe to pre-load the destination register with -1 and drop the conditional logic. However, it is common to find ffs() in a context where the optimiser knows that x is non-zero even if it the value isn't known precisely. In this case, it's safe to drop the preload of -1 too. There are only a handful of uses of ffs() in the x86 build, and all of them improve as a result of this: add/remove: 0/0 grow/shrink: 0/4 up/down: 0/-92 (-92) Function old new delta mask_write 121 113 -8 xmem_pool_alloc 1076 1056 -20 test_bitops 390 358 -32 pt_update_contig_markers 1236 1204 -32 Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> Release-acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
This commit is contained in:
1 parent
ef1dd8dff4
commit
989e5f08d3
1 file changed
+32
-5
@@ -420,12 +420,39 @@ static inline int ffsl(unsigned long x)
|
||||
|
||||
static always_inline unsigned int arch_ffs(unsigned int x)
|
||||
{
|
||||
int r;
|
||||
unsigned int r;
|
||||
|
||||
if ( __builtin_constant_p(x > 0) && x > 0 )
|
||||
{
|
||||
/*
|
||||
* A common code pattern is:
|
||||
*
|
||||
* while ( bits )
|
||||
* {
|
||||
* bit = ffs(bits);
|
||||
* ...
|
||||
*
|
||||
* and the optimiser really can work with the knowledge of x being
|
||||
* non-zero without knowing it's exact value, in which case we don't
|
||||
* need to compensate for BSF's corner cases. Otherwise...
|
||||
*/
|
||||
asm ( "bsf %[val], %[res]"
|
||||
: [res] "=r" (r)
|
||||
: [val] "rm" (x) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* ... the AMD manual states that BSF won't modify the destination
|
||||
* register if x=0. The Intel manual states that the result is
|
||||
* undefined, but the architects have said that the register is
|
||||
* written back with it's old value (zero extended as normal).
|
||||
*/
|
||||
asm ( "bsf %[val], %[res]"
|
||||
: [res] "=r" (r)
|
||||
: [val] "rm" (x), "[res]" (-1) );
|
||||
}
|
||||
|
||||
asm ( "bsf %1,%0\n\t"
|
||||
"jnz 1f\n\t"
|
||||
"mov $-1,%0\n"
|
||||
"1:" : "=r" (r) : "rm" (x));
|
||||
return r + 1;
|
||||
}
|
||||
#define arch_ffs arch_ffs
|
||||
|
||||