GNU Linux-libre 6.1.91-gnu
[releases.git] / arch / xtensa / lib / divsi3.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(__divsi3)
7
8         abi_entry_default
9 #if XCHAL_HAVE_DIV32
10         quos    a2, a2, a3
11 #else
12         xor     a7, a2, a3      /* sign = dividend ^ divisor */
13         do_abs  a6, 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, a6, a2, a8  /* udividend_shift = nsau (udividend) */
17         do_nsau a4, a3, a2, 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         movi    a2, 0           /* quotient = 0 */
24
25         /* test-subtract-and-shift loop; one quotient bit on each iteration */
26 #if XCHAL_HAVE_LOOPS
27         loopnez a4, .Lloopend
28 #endif /* XCHAL_HAVE_LOOPS */
29 .Lloop:
30         bltu    a6, a3, .Lzerobit
31         sub     a6, a6, a3
32         addi    a2, a2, 1
33 .Lzerobit:
34         slli    a2, a2, 1
35         srli    a3, a3, 1
36 #if !XCHAL_HAVE_LOOPS
37         addi    a4, a4, -1
38         bnez    a4, .Lloop
39 #endif /* !XCHAL_HAVE_LOOPS */
40 .Lloopend:
41
42         bltu    a6, a3, .Lreturn
43         addi    a2, a2, 1       /* increment if udividend >= udivisor */
44 .Lreturn:
45         neg     a5, a2
46         movltz  a2, a5, a7      /* return (sign < 0) ? -quotient : quotient */
47         abi_ret_default
48
49 .Lle_one:
50         beqz    a3, .Lerror
51         neg     a2, a6          /* if udivisor == 1, then return... */
52         movgez  a2, a6, a7      /* (sign < 0) ? -udividend : udividend */
53         abi_ret_default
54
55 .Lspecial:
56         bltu    a6, a3, .Lreturn0 /* if dividend < divisor, return 0 */
57         movi    a2, 1
58         movi    a4, -1
59         movltz  a2, a4, a7      /* else return (sign < 0) ? -1 : 1 */
60         abi_ret_default
61
62 .Lerror:
63         /* Divide by zero: Use an illegal instruction to force an exception.
64            The subsequent "DIV0" string can be recognized by the exception
65            handler to identify the real cause of the exception.  */
66         ill
67         .ascii  "DIV0"
68
69 .Lreturn0:
70         movi    a2, 0
71 #endif /* XCHAL_HAVE_DIV32 */
72         abi_ret_default
73
74 ENDPROC(__divsi3)