xref: /linux/arch/x86/include/asm/div64.h (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
1 #ifndef _ASM_X86_DIV64_H
2 #define _ASM_X86_DIV64_H
3 
4 #ifdef CONFIG_X86_32
5 
6 #include <linux/types.h>
7 
8 /*
9  * do_div() is NOT a C function. It wants to return
10  * two values (the quotient and the remainder), but
11  * since that doesn't work very well in C, what it
12  * does is:
13  *
14  * - modifies the 64-bit dividend _in_place_
15  * - returns the 32-bit remainder
16  *
17  * This ends up being the most efficient "calling
18  * convention" on x86.
19  */
20 #define do_div(n, base)						\
21 ({								\
22 	unsigned long __upper, __low, __high, __mod, __base;	\
23 	__base = (base);					\
24 	asm("":"=a" (__low), "=d" (__high) : "A" (n));		\
25 	__upper = __high;					\
26 	if (__high) {						\
27 		__upper = __high % (__base);			\
28 		__high = __high / (__base);			\
29 	}							\
30 	asm("divl %2":"=a" (__low), "=d" (__mod)		\
31 	    : "rm" (__base), "0" (__low), "1" (__upper));	\
32 	asm("":"=A" (n) : "a" (__low), "d" (__high));		\
33 	__mod;							\
34 })
35 
36 static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
37 {
38 	union {
39 		u64 v64;
40 		u32 v32[2];
41 	} d = { dividend };
42 	u32 upper;
43 
44 	upper = d.v32[1];
45 	d.v32[1] = 0;
46 	if (upper >= divisor) {
47 		d.v32[1] = upper / divisor;
48 		upper %= divisor;
49 	}
50 	asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
51 		"rm" (divisor), "0" (d.v32[0]), "1" (upper));
52 	return d.v64;
53 }
54 #define div_u64_rem	div_u64_rem
55 
56 #else
57 # include <asm-generic/div64.h>
58 #endif /* CONFIG_X86_32 */
59 
60 #endif /* _ASM_X86_DIV64_H */
61