Home | History | Annotate | Download | only in asm-x86
      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 	unsigned long __upper, __low, __high, __mod, __base; \
     22 	__base = (base); \
     23 	asm("":"=a" (__low), "=d" (__high):"A" (n)); \
     24 	__upper = __high; \
     25 	if (__high) { \
     26 		__upper = __high % (__base); \
     27 		__high = __high / (__base); \
     28 	} \
     29 	asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
     30 	asm("":"=A" (n):"a" (__low),"d" (__high)); \
     31 	__mod; \
     32 })
     33 
     34 /*
     35  * (long)X = ((long long)divs) / (long)div
     36  * (long)rem = ((long long)divs) % (long)div
     37  *
     38  * Warning, this will do an exception if X overflows.
     39  */
     40 #define div_long_long_rem(a,b,c) div_ll_X_l_rem(a,b,c)
     41 
     42 static inline long
     43 div_ll_X_l_rem(long long divs, long div, long *rem)
     44 {
     45 	long dum2;
     46       __asm__("divl %2":"=a"(dum2), "=d"(*rem)
     47       :	"rm"(div), "A"(divs));
     48 
     49 	return dum2;
     50 
     51 }
     52 
     53 extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
     54 
     55 #else
     56 # include <asm-generic/div64.h>
     57 #endif /* CONFIG_X86_32 */
     58 
     59 #endif /* _ASM_X86_DIV64_H */
     60