Skip to content

Commit bb1f115

Browse files
committed
Merge tag 'x86_asm_for_v6.1_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm update from Borislav Petkov: - Use the __builtin_ffs/ctzl() compiler builtins for the constant argument case in the kernel's optimized ffs()/ffz() helpers in order to make use of the compiler's constant folding optmization passes. * tag 'x86_asm_for_v6.1_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/asm/bitops: Use __builtin_ctzl() to evaluate constant expressions x86/asm/bitops: Use __builtin_ffs() to evaluate constant expressions
2 parents 8cded8f + fdb6649 commit bb1f115

File tree

1 file changed

+33
-21
lines changed

1 file changed

+33
-21
lines changed

arch/x86/include/asm/bitops.h

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -247,17 +247,30 @@ arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
247247
variable_test_bit(nr, addr);
248248
}
249249

250+
static __always_inline unsigned long variable__ffs(unsigned long word)
251+
{
252+
asm("rep; bsf %1,%0"
253+
: "=r" (word)
254+
: "rm" (word));
255+
return word;
256+
}
257+
250258
/**
251259
* __ffs - find first set bit in word
252260
* @word: The word to search
253261
*
254262
* Undefined if no bit exists, so code should check against 0 first.
255263
*/
256-
static __always_inline unsigned long __ffs(unsigned long word)
264+
#define __ffs(word) \
265+
(__builtin_constant_p(word) ? \
266+
(unsigned long)__builtin_ctzl(word) : \
267+
variable__ffs(word))
268+
269+
static __always_inline unsigned long variable_ffz(unsigned long word)
257270
{
258271
asm("rep; bsf %1,%0"
259272
: "=r" (word)
260-
: "rm" (word));
273+
: "r" (~word));
261274
return word;
262275
}
263276

@@ -267,13 +280,10 @@ static __always_inline unsigned long __ffs(unsigned long word)
267280
*
268281
* Undefined if no zero exists, so code should check against ~0UL first.
269282
*/
270-
static __always_inline unsigned long ffz(unsigned long word)
271-
{
272-
asm("rep; bsf %1,%0"
273-
: "=r" (word)
274-
: "r" (~word));
275-
return word;
276-
}
283+
#define ffz(word) \
284+
(__builtin_constant_p(word) ? \
285+
(unsigned long)__builtin_ctzl(~word) : \
286+
variable_ffz(word))
277287

278288
/*
279289
* __fls: find last set bit in word
@@ -292,18 +302,7 @@ static __always_inline unsigned long __fls(unsigned long word)
292302
#undef ADDR
293303

294304
#ifdef __KERNEL__
295-
/**
296-
* ffs - find first set bit in word
297-
* @x: the word to search
298-
*
299-
* This is defined the same way as the libc and compiler builtin ffs
300-
* routines, therefore differs in spirit from the other bitops.
301-
*
302-
* ffs(value) returns 0 if value is 0 or the position of the first
303-
* set bit if value is nonzero. The first (least significant) bit
304-
* is at position 1.
305-
*/
306-
static __always_inline int ffs(int x)
305+
static __always_inline int variable_ffs(int x)
307306
{
308307
int r;
309308

@@ -333,6 +332,19 @@ static __always_inline int ffs(int x)
333332
return r + 1;
334333
}
335334

335+
/**
336+
* ffs - find first set bit in word
337+
* @x: the word to search
338+
*
339+
* This is defined the same way as the libc and compiler builtin ffs
340+
* routines, therefore differs in spirit from the other bitops.
341+
*
342+
* ffs(value) returns 0 if value is 0 or the position of the first
343+
* set bit if value is nonzero. The first (least significant) bit
344+
* is at position 1.
345+
*/
346+
#define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))
347+
336348
/**
337349
* fls - find last set bit in word
338350
* @x: the word to search

0 commit comments

Comments
 (0)