GNU Linux-libre 6.1.91-gnu
[releases.git] / arch / xtensa / lib / umodsi3.S
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)