xref: /linux/arch/xtensa/lib/umodsi3.S (revision 1b0975ee3bdd3eb19a47371c26fd7ef8f7f6b599)
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
6ENTRY(__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
57ENDPROC(__umodsi3)
58EXPORT_SYMBOL(__umodsi3)
59