GNU Linux-libre 6.1.91-gnu
[releases.git] / arch / xtensa / lib / modsi3.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(__modsi3)
7
8         abi_entry_default
9 #if XCHAL_HAVE_DIV32
10         rems    a2, a2, a3
11 #else
12         mov     a7, a2          /* save original (signed) dividend */
13         do_abs  a2, a2, a4      /* udividend = abs (dividend) */
14         do_abs  a3, a3, a4      /* udivisor = abs (divisor) */
15         bltui   a3, 2, .Lle_one /* check if udivisor <= 1 */
16         do_nsau a5, a2, a6, a8  /* udividend_shift = nsau (udividend) */
17         do_nsau a4, a3, a6, a8  /* udivisor_shift = nsau (udivisor) */
18         bgeu    a5, a4, .Lspecial
19
20         sub     a4, a4, a5      /* count = udivisor_shift - udividend_shift */
21         ssl     a4
22         sll     a3, a3          /* udivisor <<= count */
23
24         /* test-subtract-and-shift loop */
25 #if XCHAL_HAVE_LOOPS
26         loopnez a4, .Lloopend
27 #endif /* XCHAL_HAVE_LOOPS */
28 .Lloop:
29         bltu    a2, a3, .Lzerobit
30         sub     a2, a2, a3
31 .Lzerobit:
32         srli    a3, a3, 1
33 #if !XCHAL_HAVE_LOOPS
34         addi    a4, a4, -1
35         bnez    a4, .Lloop
36 #endif /* !XCHAL_HAVE_LOOPS */
37 .Lloopend:
38
39 .Lspecial:
40         bltu    a2, a3, .Lreturn
41         sub     a2, a2, a3      /* subtract again if udividend >= udivisor */
42 .Lreturn:
43         bgez    a7, .Lpositive
44         neg     a2, a2          /* if (dividend < 0), return -udividend */
45 .Lpositive:
46         abi_ret_default
47
48 .Lle_one:
49         bnez    a3, .Lreturn0
50
51         /* Divide by zero: Use an illegal instruction to force an exception.
52            The subsequent "DIV0" string can be recognized by the exception
53            handler to identify the real cause of the exception.  */
54         ill
55         .ascii  "DIV0"
56
57 .Lreturn0:
58         movi    a2, 0
59 #endif /* XCHAL_HAVE_DIV32 */
60         abi_ret_default
61
62 ENDPROC(__modsi3)
63
64 #if !XCHAL_HAVE_NSA
65         .section .rodata
66         .align  4
67         .global __nsau_data
68         .type   __nsau_data, @object
69 __nsau_data:
70         .byte   8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4
71         .byte   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
72         .byte   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
73         .byte   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
74         .byte   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
75         .byte   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
76         .byte   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
77         .byte   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
78         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
79         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
80         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
81         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
82         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
83         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
84         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
85         .byte   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
86         .size   __nsau_data, . - __nsau_data
87 #endif /* !XCHAL_HAVE_NSA */