1 /* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */
2 #include <linux/linkage.h>
3 #include <asm/asmmacro.h>
4 #include <asm/core.h>
5 
6 ENTRY(__umodsi3)
7 
8 	abi_entry_default
9 #if XCHAL_HAVE_DIV32
10 	remu	a2, a2, a3
11 #else
12 	bltui	a3, 2, .Lle_one	/* check if the divisor is <= 1 */
13 
14 	do_nsau	a5, a2, a6, a7	/* dividend_shift = nsau (dividend) */
15 	do_nsau	a4, a3, a6, a7	/* divisor_shift = nsau (divisor) */
16 	bgeu	a5, a4, .Lspecial
17 
18 	sub	a4, a4, a5	/* count = divisor_shift - dividend_shift */
19 	ssl	a4
20 	sll	a3, a3		/* divisor <<= count */
21 
22 	/* test-subtract-and-shift loop */
23 #if XCHAL_HAVE_LOOPS
24 	loopnez	a4, .Lloopend
25 #endif /* XCHAL_HAVE_LOOPS */
26 .Lloop:
27 	bltu	a2, a3, .Lzerobit
28 	sub	a2, a2, a3
29 .Lzerobit:
30 	srli	a3, a3, 1
31 #if !XCHAL_HAVE_LOOPS
32 	addi	a4, a4, -1
33 	bnez	a4, .Lloop
34 #endif /* !XCHAL_HAVE_LOOPS */
35 .Lloopend:
36 
37 .Lspecial:
38 	bltu	a2, a3, .Lreturn
39 	sub	a2, a2, a3	/* subtract once more if dividend >= divisor */
40 .Lreturn:
41 	abi_ret_default
42 
43 .Lle_one:
44 	bnez	a3, .Lreturn0
45 
46 	/* Divide by zero: Use an illegal instruction to force an exception.
47 	   The subsequent "DIV0" string can be recognized by the exception
48 	   handler to identify the real cause of the exception.  */
49 	ill
50 	.ascii	"DIV0"
51 
52 .Lreturn0:
53 	movi	a2, 0
54 #endif /* XCHAL_HAVE_DIV32 */
55 	abi_ret_default
56 
57 ENDPROC(__umodsi3)
58 EXPORT_SYMBOL(__umodsi3)
59