Commit bb1f1154 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 8cded8fb fdb6649a
Loading
Loading
Loading
Loading
+33 −21
Original line number Diff line number Diff line
@@ -247,17 +247,30 @@ arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
					  variable_test_bit(nr, addr);
}

static __always_inline unsigned long variable__ffs(unsigned long word)
{
	asm("rep; bsf %1,%0"
		: "=r" (word)
		: "rm" (word));
	return word;
}

/**
 * __ffs - find first set bit in word
 * @word: The word to search
 *
 * Undefined if no bit exists, so code should check against 0 first.
 */
static __always_inline unsigned long __ffs(unsigned long word)
#define __ffs(word)				\
	(__builtin_constant_p(word) ?		\
	 (unsigned long)__builtin_ctzl(word) :	\
	 variable__ffs(word))

static __always_inline unsigned long variable_ffz(unsigned long word)
{
	asm("rep; bsf %1,%0"
		: "=r" (word)
		: "rm" (word));
		: "r" (~word));
	return word;
}

@@ -267,13 +280,10 @@ static __always_inline unsigned long __ffs(unsigned long word)
 *
 * Undefined if no zero exists, so code should check against ~0UL first.
 */
static __always_inline unsigned long ffz(unsigned long word)
{
	asm("rep; bsf %1,%0"
		: "=r" (word)
		: "r" (~word));
	return word;
}
#define ffz(word)				\
	(__builtin_constant_p(word) ?		\
	 (unsigned long)__builtin_ctzl(~word) :	\
	 variable_ffz(word))

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

#ifdef __KERNEL__
/**
 * ffs - find first set bit in word
 * @x: the word to search
 *
 * This is defined the same way as the libc and compiler builtin ffs
 * routines, therefore differs in spirit from the other bitops.
 *
 * ffs(value) returns 0 if value is 0 or the position of the first
 * set bit if value is nonzero. The first (least significant) bit
 * is at position 1.
 */
static __always_inline int ffs(int x)
static __always_inline int variable_ffs(int x)
{
	int r;

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

/**
 * ffs - find first set bit in word
 * @x: the word to search
 *
 * This is defined the same way as the libc and compiler builtin ffs
 * routines, therefore differs in spirit from the other bitops.
 *
 * ffs(value) returns 0 if value is 0 or the position of the first
 * set bit if value is nonzero. The first (least significant) bit
 * is at position 1.
 */
#define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))

/**
 * fls - find last set bit in word
 * @x: the word to search