Skip to content

Commit 25ab14c

Browse files
maciej-w-rozyckitsbogend
authored andcommitted
MIPS: Avoid handcoded DIVU in `__div64_32' altogether
Remove the inline asm with a DIVU instruction from `__div64_32' and use plain C code for the intended DIVMOD calculation instead. GCC is smart enough to know that both the quotient and the remainder are calculated with single DIVU, so with ISAs up to R5 the same instruction is actually produced with overall similar code. For R6 compiled code will work, but separate DIVU and MODU instructions will be produced, which are also interlocked, so scalar implementations will likely not perform as well as older ISAs with their asynchronous MD unit. Likely still faster then the generic algorithm though. This removes a compilation error for R6 however where the original DIVU instruction is not supported anymore and the MDU accumulator registers have been removed and consequently GCC complains as to a constraint it cannot find a register for: In file included from ./include/linux/math.h:5, from ./include/linux/kernel.h:13, from mm/page-writeback.c:15: ./include/linux/math64.h: In function 'div_u64_rem': ./arch/mips/include/asm/div64.h:76:17: error: inconsistent operand constraints in an 'asm' 76 | __asm__("divu $0, %z1, %z2" \ | ^~~~~~~ ./include/asm-generic/div64.h:245:25: note: in expansion of macro '__div64_32' 245 | __rem = __div64_32(&(n), __base); \ | ^~~~~~~~~~ ./include/linux/math64.h:91:22: note: in expansion of macro 'do_div' 91 | *remainder = do_div(dividend, divisor); | ^~~~~~ This has passed correctness verification with test_div64 and reduced the module's average execution time down to 1.0404s from 1.0445s with R3400 @40MHz. The module's MIPS I machine code has also shrunk by 12 bytes or 3 instructions. Signed-off-by: Maciej W. Rozycki <[email protected]> Signed-off-by: Thomas Bogendoerfer <[email protected]>
1 parent 517b322 commit 25ab14c

File tree

1 file changed

+2
-6
lines changed

1 file changed

+2
-6
lines changed

arch/mips/include/asm/div64.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858

5959
#define __div64_32(n, base) ({ \
6060
unsigned long __upper, __low, __high, __radix; \
61-
unsigned long long __modquot; \
6261
unsigned long long __quot; \
6362
unsigned long long __div; \
6463
unsigned long __mod; \
@@ -73,11 +72,8 @@
7372
__upper = __high; \
7473
__high = 0; \
7574
} else { \
76-
__asm__("divu $0, %z1, %z2" \
77-
: "=x" (__modquot) \
78-
: "Jr" (__high), "Jr" (__radix)); \
79-
__upper = __modquot >> 32; \
80-
__high = __modquot; \
75+
__upper = __high % __radix; \
76+
__high /= __radix; \
8177
} \
8278
\
8379
__mod = do_div64_32(__low, __upper, __low, __radix); \

0 commit comments

Comments
 (0)