diff options
Diffstat (limited to 'arch/x86/include/asm/div64.h')
| -rw-r--r-- | arch/x86/include/asm/div64.h | 22 | 
1 files changed, 14 insertions, 8 deletions
diff --git a/arch/x86/include/asm/div64.h b/arch/x86/include/asm/div64.h index 9a2d644c08e..ced283ac79d 100644 --- a/arch/x86/include/asm/div64.h +++ b/arch/x86/include/asm/div64.h @@ -4,6 +4,7 @@  #ifdef CONFIG_X86_32  #include <linux/types.h> +#include <linux/log2.h>  /*   * do_div() is NOT a C function. It wants to return @@ -21,15 +22,20 @@  ({								\  	unsigned long __upper, __low, __high, __mod, __base;	\  	__base = (base);					\ -	asm("":"=a" (__low), "=d" (__high) : "A" (n));		\ -	__upper = __high;					\ -	if (__high) {						\ -		__upper = __high % (__base);			\ -		__high = __high / (__base);			\ +	if (__builtin_constant_p(__base) && is_power_of_2(__base)) { \ +		__mod = n & (__base - 1);			\ +		n >>= ilog2(__base);				\ +	} else {						\ +		asm("" : "=a" (__low), "=d" (__high) : "A" (n));\ +		__upper = __high;				\ +		if (__high) {					\ +			__upper = __high % (__base);		\ +			__high = __high / (__base);		\ +		}						\ +		asm("divl %2" : "=a" (__low), "=d" (__mod)	\ +			: "rm" (__base), "0" (__low), "1" (__upper));	\ +		asm("" : "=A" (n) : "a" (__low), "d" (__high));	\  	}							\ -	asm("divl %2":"=a" (__low), "=d" (__mod)		\ -	    : "rm" (__base), "0" (__low), "1" (__upper));	\ -	asm("":"=A" (n) : "a" (__low), "d" (__high));		\  	__mod;							\  })  |