[docs] Update HowToReleaseLLVM documentation.
[llvm-project.git] / compiler-rt / lib / builtins / arm / udivmodsi4.S
blob0f40575fe99ea4ae21f117382c08eae97ef117c9
1 //===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the __udivmodsi4 (32-bit unsigned integer divide and
10 // modulus) function for the ARM 32-bit architecture.
12 //===----------------------------------------------------------------------===//
14 #include "../assembly.h"
16         .syntax unified
17         .text
18         DEFINE_CODE_STATE
20 @ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
21 @                           unsigned int *remainder)
22 @   Calculate the quotient and remainder of the (unsigned) division.  The return
23 @   value is the quotient, the remainder is placed in the variable.
25         .p2align 2
26 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
27 #if __ARM_ARCH_EXT_IDIV__
28         tst     r1, r1
29         beq     LOCAL_LABEL(divby0)
30         mov     r3, r0
31         udiv    r0, r3, r1
32         mls     r1, r0, r1, r3
33         str     r1, [r2]
34         bx      lr
35 #else
36         cmp     r1, #1
37         bcc     LOCAL_LABEL(divby0)
38         beq     LOCAL_LABEL(divby1)
39         cmp     r0, r1
40         bcc     LOCAL_LABEL(quotient0)
42         // Implement division using binary long division algorithm.
43         //
44         // r0 is the numerator, r1 the denominator.
45         //
46         // The code before JMP computes the correct shift I, so that
47         // r0 and (r1 << I) have the highest bit set in the same position.
48         // At the time of JMP, ip := .Ldiv0block - 12 * I.
49         // This depends on the fixed instruction size of block.
50         // For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
51         //
52         // block(shift) implements the test-and-update-quotient core.
53         // It assumes (r0 << shift) can be computed without overflow and
54         // that (r0 << shift) < 2 * r1. The quotient is stored in r3.
56 #  ifdef __ARM_FEATURE_CLZ
57         clz     ip, r0
58         clz     r3, r1
59         // r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
60         sub     r3, r3, ip
61 #    if defined(USE_THUMB_2)
62         adr     ip, LOCAL_LABEL(div0block) + 1
63         sub     ip, ip, r3, lsl #1
64 #    else
65         adr     ip, LOCAL_LABEL(div0block)
66 #    endif
67         sub     ip, ip, r3, lsl #2
68         sub     ip, ip, r3, lsl #3
69         mov     r3, #0
70         bx      ip
71 #  else
72 #    if defined(USE_THUMB_2)
73 #    error THUMB mode requires CLZ or UDIV
74 #    endif
75         str     r4, [sp, #-8]!
77         mov     r4, r0
78         adr     ip, LOCAL_LABEL(div0block)
80         lsr     r3, r4, #16
81         cmp     r3, r1
82         movhs   r4, r3
83         subhs   ip, ip, #(16 * 12)
85         lsr     r3, r4, #8
86         cmp     r3, r1
87         movhs   r4, r3
88         subhs   ip, ip, #(8 * 12)
90         lsr     r3, r4, #4
91         cmp     r3, r1
92         movhs   r4, r3
93         subhs   ip, #(4 * 12)
95         lsr     r3, r4, #2
96         cmp     r3, r1
97         movhs   r4, r3
98         subhs   ip, ip, #(2 * 12)
100         // Last block, no need to update r3 or r4.
101         cmp     r1, r4, lsr #1
102         subls   ip, ip, #(1 * 12)
104         ldr     r4, [sp], #8    // restore r4, we are done with it.
105         mov     r3, #0
107         JMP(ip)
108 #  endif
110 #define IMM     #
112 #define block(shift)                                                           \
113         cmp     r0, r1, lsl IMM shift;                                         \
114         ITT(hs);                                                               \
115         WIDE(addhs)     r3, r3, IMM (1 << shift);                              \
116         WIDE(subhs)     r0, r0, r1, lsl IMM shift
118         block(31)
119         block(30)
120         block(29)
121         block(28)
122         block(27)
123         block(26)
124         block(25)
125         block(24)
126         block(23)
127         block(22)
128         block(21)
129         block(20)
130         block(19)
131         block(18)
132         block(17)
133         block(16)
134         block(15)
135         block(14)
136         block(13)
137         block(12)
138         block(11)
139         block(10)
140         block(9)
141         block(8)
142         block(7)
143         block(6)
144         block(5)
145         block(4)
146         block(3)
147         block(2)
148         block(1)
149 LOCAL_LABEL(div0block):
150         block(0)
152         str     r0, [r2]
153         mov     r0, r3
154         JMP(lr)
156 LOCAL_LABEL(quotient0):
157         str     r0, [r2]
158         mov     r0, #0
159         JMP(lr)
161 LOCAL_LABEL(divby1):
162         mov     r3, #0
163         str     r3, [r2]
164         JMP(lr)
165 #endif // __ARM_ARCH_EXT_IDIV__
167 LOCAL_LABEL(divby0):
168         mov     r0, #0
169 #ifdef __ARM_EABI__
170         b       __aeabi_idiv0
171 #else
172         JMP(lr)
173 #endif
175 END_COMPILERRT_FUNCTION(__udivmodsi4)
177 NO_EXEC_STACK_DIRECTIVE