]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/compiler-rt/lib/builtins/arm/umodsi3.S
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / compiler-rt / lib / builtins / arm / umodsi3.S
1 //===-- umodsi3.S - 32-bit unsigned integer 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 __umodsi3 (32-bit unsigned integer modulus)
10 // function for the ARM 32-bit architecture.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "../assembly.h"
15
16         .syntax unified
17         .text
18         DEFINE_CODE_STATE
19
20 @ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
21 @   Calculate and return the remainder of the (unsigned) division.
22
23         .p2align 2
24 DEFINE_COMPILERRT_FUNCTION(__umodsi3)
25 #if __ARM_ARCH_EXT_IDIV__
26         tst     r1, r1
27         beq     LOCAL_LABEL(divby0)
28         udiv    r2, r0, r1
29         mls     r0, r2, r1, r0
30         bx      lr
31 #else
32         cmp     r1, #1
33         bcc     LOCAL_LABEL(divby0)
34         ITT(eq)
35         moveq   r0, #0
36         JMPc(lr, eq)
37         cmp     r0, r1
38         IT(cc)
39         JMPc(lr, cc)
40
41         // Implement division using binary long division algorithm.
42         //
43         // r0 is the numerator, r1 the denominator.
44         //
45         // The code before JMP computes the correct shift I, so that
46         // r0 and (r1 << I) have the highest bit set in the same position.
47         // At the time of JMP, ip := .Ldiv0block - 8 * I.
48         // This depends on the fixed instruction size of block.
49         // For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
50         //
51         // block(shift) implements the test-and-update-quotient core.
52         // It assumes (r0 << shift) can be computed without overflow and
53         // that (r0 << shift) < 2 * r1. The quotient is stored in r3.
54
55 #  ifdef __ARM_FEATURE_CLZ
56         clz     ip, r0
57         clz     r3, r1
58         // r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
59         sub     r3, r3, ip
60 #    if defined(USE_THUMB_2)
61         adr     ip, LOCAL_LABEL(div0block) + 1
62         sub     ip, ip, r3, lsl #1
63 #    else
64         adr     ip, LOCAL_LABEL(div0block)
65 #    endif
66         sub     ip, ip, r3, lsl #3
67         bx      ip
68 #  else
69 #    if defined(USE_THUMB_2)
70 #    error THUMB mode requires CLZ or UDIV
71 #    endif
72         mov     r2, r0
73         adr     ip, LOCAL_LABEL(div0block)
74
75         lsr     r3, r2, #16
76         cmp     r3, r1
77         movhs   r2, r3
78         subhs   ip, ip, #(16 * 8)
79
80         lsr     r3, r2, #8
81         cmp     r3, r1
82         movhs   r2, r3
83         subhs   ip, ip, #(8 * 8)
84
85         lsr     r3, r2, #4
86         cmp     r3, r1
87         movhs   r2, r3
88         subhs   ip, #(4 * 8)
89
90         lsr     r3, r2, #2
91         cmp     r3, r1
92         movhs   r2, r3
93         subhs   ip, ip, #(2 * 8)
94
95         // Last block, no need to update r2 or r3.
96         cmp     r1, r2, lsr #1
97         subls   ip, ip, #(1 * 8)
98
99         JMP(ip)
100 #  endif
101
102 #define IMM     #
103
104 #define block(shift)                                                           \
105         cmp     r0, r1, lsl IMM shift;                                         \
106         IT(hs);                                                                \
107         WIDE(subhs)     r0, r0, r1, lsl IMM shift
108
109         block(31)
110         block(30)
111         block(29)
112         block(28)
113         block(27)
114         block(26)
115         block(25)
116         block(24)
117         block(23)
118         block(22)
119         block(21)
120         block(20)
121         block(19)
122         block(18)
123         block(17)
124         block(16)
125         block(15)
126         block(14)
127         block(13)
128         block(12)
129         block(11)
130         block(10)
131         block(9)
132         block(8)
133         block(7)
134         block(6)
135         block(5)
136         block(4)
137         block(3)
138         block(2)
139         block(1)
140 LOCAL_LABEL(div0block):
141         block(0)
142         JMP(lr)
143 #endif // __ARM_ARCH_EXT_IDIV__
144
145 LOCAL_LABEL(divby0):
146         mov     r0, #0
147 #ifdef __ARM_EABI__
148         b       __aeabi_idiv0
149 #else
150         JMP(lr)
151 #endif
152
153 END_COMPILERRT_FUNCTION(__umodsi3)
154
155 NO_EXEC_STACK_DIRECTIVE
156