xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/config/riscv/div.S (revision aef5eb5f59cdfe8314f1b5f78ac04eb144e44010)
1/* Integer division routines for RISC-V.
2
3   Copyright (C) 2016-2020 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24<http://www.gnu.org/licenses/>.  */
25
26#include "riscv-asm.h"
27
28  .text
29  .align 2
30
31#if __riscv_xlen == 32
32/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines.  */
33# define __udivdi3 __udivsi3
34# define __umoddi3 __umodsi3
35# define __divdi3 __divsi3
36# define __moddi3 __modsi3
37#else
38FUNC_BEGIN (__udivsi3)
39  /* Compute __udivdi3(a0 << 32, a1 << 32); cast result to uint32_t.  */
40  sll    a0, a0, 32
41  sll    a1, a1, 32
42  move   t0, ra
43  jal    __udivdi3
44  sext.w a0, a0
45  jr     t0
46FUNC_END (__udivsi3)
47
48FUNC_BEGIN (__umodsi3)
49  /* Compute __udivdi3((uint32_t)a0, (uint32_t)a1); cast a1 to uint32_t.  */
50  sll    a0, a0, 32
51  sll    a1, a1, 32
52  srl    a0, a0, 32
53  srl    a1, a1, 32
54  move   t0, ra
55  jal    __udivdi3
56  sext.w a0, a1
57  jr     t0
58FUNC_END (__umodsi3)
59
60FUNC_ALIAS (__modsi3, __moddi3)
61
62FUNC_BEGIN( __divsi3)
63  /* Check for special case of INT_MIN/-1. Otherwise, fall into __divdi3.  */
64  li    t0, -1
65  beq   a1, t0, .L20
66#endif
67
68FUNC_BEGIN (__divdi3)
69  bltz  a0, .L10
70  bltz  a1, .L11
71  /* Since the quotient is positive, fall into __udivdi3.  */
72
73FUNC_BEGIN (__udivdi3)
74  mv    a2, a1
75  mv    a1, a0
76  li    a0, -1
77  beqz  a2, .L5
78  li    a3, 1
79  bgeu  a2, a1, .L2
80.L1:
81  blez  a2, .L2
82  slli  a2, a2, 1
83  slli  a3, a3, 1
84  bgtu  a1, a2, .L1
85.L2:
86  li    a0, 0
87.L3:
88  bltu  a1, a2, .L4
89  sub   a1, a1, a2
90  or    a0, a0, a3
91.L4:
92  srli  a3, a3, 1
93  srli  a2, a2, 1
94  bnez  a3, .L3
95.L5:
96  ret
97FUNC_END (__udivdi3)
98
99FUNC_BEGIN (__umoddi3)
100  /* Call __udivdi3(a0, a1), then return the remainder, which is in a1.  */
101  move  t0, ra
102  jal   __udivdi3
103  move  a0, a1
104  jr    t0
105FUNC_END (__umoddi3)
106
107  /* Handle negative arguments to __divdi3.  */
108.L10:
109  neg   a0, a0
110  bgez  a1, .L12      /* Compute __udivdi3(-a0, a1), then negate the result.  */
111  neg   a1, a1
112  j     __udivdi3     /* Compute __udivdi3(-a0, -a1).  */
113.L11:                 /* Compute __udivdi3(a0, -a1), then negate the result.  */
114  neg   a1, a1
115.L12:
116  move  t0, ra
117  jal   __udivdi3
118  neg   a0, a0
119  jr    t0
120FUNC_END (__divdi3)
121
122FUNC_BEGIN (__moddi3)
123  move   t0, ra
124  bltz   a1, .L31
125  bltz   a0, .L32
126.L30:
127  jal    __udivdi3    /* The dividend is not negative.  */
128  move   a0, a1
129  jr     t0
130.L31:
131  neg    a1, a1
132  bgez   a0, .L30
133.L32:
134  neg    a0, a0
135  jal    __udivdi3    /* The dividend is hella negative.  */
136  neg    a0, a1
137  jr     t0
138FUNC_END (__moddi3)
139
140#if __riscv_xlen == 64
141  /* continuation of __divsi3 */
142.L20:
143  sll   t0, t0, 31
144  bne   a0, t0, __divdi3
145  ret
146FUNC_END (__divsi3)
147#endif
148