xref: /optee_os/lib/libutils/isoc/arch/arm/arm32_aeabi_divmod.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Form ABI specifications:
31  *      int __aeabi_idiv(int numerator, int denominator);
32  *     unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
33  *
34  *     typedef struct { int quot; int rem; } idiv_return;
35  *     typedef struct { unsigned quot; unsigned rem; } uidiv_return;
36  *
37  *     __value_in_regs idiv_return __aeabi_idivmod(int numerator,
38  *     int *denominator);
39  *     __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
40  *     unsigned denominator);
41  */
42 
43 /* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */
44 struct qr {
45 	unsigned q;		/* computed quotient */
46 	unsigned r;		/* computed remainder */
47 	unsigned q_n;		/* specficies if quotient shall be negative */
48 	unsigned r_n;		/* specficies if remainder shall be negative */
49 };
50 
51 static void uint_div_qr(unsigned numerator, unsigned denominator,
52 			struct qr *qr);
53 
54 /* returns in R0 and R1 by tail calling an asm function */
55 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator);
56 
57 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
58 unsigned __aeabi_uimod(unsigned numerator, unsigned denominator);
59 
60 /* returns in R0 and R1 by tail calling an asm function */
61 signed __aeabi_idivmod(signed numerator, signed denominator);
62 
63 signed __aeabi_idiv(signed numerator, signed denominator);
64 signed __aeabi_imod(signed numerator, signed denominator);
65 
66 /*
67  * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
68  * Numerator and Denominator are received in R0 and R1.
69  * Where __ste_idivmod_ret_t is returned in R0 and R1.
70  *
71  * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
72  *                                       unsigned denominator)
73  * Numerator and Denominator are received in R0 and R1.
74  * Where __ste_uidivmod_ret_t is returned in R0 and R1.
75  */
76 #ifdef __GNUC__
77 signed ret_idivmod_values(signed quotient, signed remainder);
78 unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder);
79 #else
80 #error "Compiler not supported"
81 #endif
82 
83 static void division_qr(unsigned n, unsigned p, struct qr *qr)
84 {
85 	unsigned i = 1, q = 0;
86 	if (p == 0) {
87 		qr->r = 0xFFFFFFFF;	/* division by 0 */
88 		return;
89 	}
90 
91 	while ((p >> 31) == 0) {
92 		i = i << 1;	/* count the max division steps */
93 		p = p << 1;     /* increase p until it has maximum size*/
94 	}
95 
96 	while (i > 0) {
97 		q = q << 1;	/* write bit in q at index (size-1) */
98 		if (n >= p)
99 		{
100 			n -= p;
101 			q++;
102 		}
103 		p = p >> 1; 	/* decrease p */
104 		i = i >> 1; 	/* decrease remaining size in q */
105 	}
106 	qr->r = n;
107 	qr->q = q;
108 }
109 
110 static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr)
111 {
112 
113 	division_qr(numerator, denominator, qr);
114 
115 	/* negate quotient and/or remainder according to requester */
116 	if (qr->q_n)
117 		qr->q = -qr->q;
118 	if (qr->r_n)
119 		qr->r = -qr->r;
120 }
121 
122 unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
123 {
124 	struct qr qr = { .q_n = 0, .r_n = 0 };
125 
126 	uint_div_qr(numerator, denominator, &qr);
127 
128 	return qr.q;
129 }
130 
131 unsigned __aeabi_uimod(unsigned numerator, unsigned denominator)
132 {
133 	struct qr qr = { .q_n = 0, .r_n = 0 };
134 
135 	uint_div_qr(numerator, denominator, &qr);
136 
137 	return qr.r;
138 }
139 
140 unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator)
141 {
142 	struct qr qr = { .q_n = 0, .r_n = 0 };
143 
144 	uint_div_qr(numerator, denominator, &qr);
145 
146 	return ret_uidivmod_values(qr.q, qr.r);
147 }
148 
149 signed __aeabi_idiv(signed numerator, signed denominator)
150 {
151 	struct qr qr = { .q_n = 0, .r_n = 0 };
152 
153 	if (((numerator < 0) && (denominator > 0)) ||
154 	    ((numerator > 0) && (denominator < 0)))
155 		qr.q_n = 1;	/* quotient shall be negate */
156 	if (numerator < 0) {
157 		numerator = -numerator;
158 		qr.r_n = 1;	/* remainder shall be negate */
159 	}
160 	if (denominator < 0)
161 		denominator = -denominator;
162 
163 	uint_div_qr(numerator, denominator, &qr);
164 
165 	return qr.q;
166 }
167 
168 signed __aeabi_imod(signed numerator, signed denominator)
169 {
170 	signed s;
171 	signed i;
172 	signed j;
173 	signed h;
174 
175 	struct qr qr = { .q_n = 0, .r_n = 0 };
176 
177 	/* in case modulo of a power of 2 */
178 	for (i = 0, j = 0, h = 0, s = denominator; (s != 0) || (h > 1); i++) {
179 		if (s & 1) {
180 			j = i;
181 			h++;
182 		}
183 		s = s >> 1;
184 	}
185 	if (h == 1)
186 		return numerator >> j;
187 
188 	if (((numerator < 0) && (denominator > 0)) ||
189 	    ((numerator > 0) && (denominator < 0)))
190 		qr.q_n = 1;	/* quotient shall be negate */
191 	if (numerator < 0) {
192 		numerator = -numerator;
193 		qr.r_n = 1;	/* remainder shall be negate */
194 	}
195 	if (denominator < 0)
196 		denominator = -denominator;
197 
198 	uint_div_qr(numerator, denominator, &qr);
199 
200 	return qr.r;
201 }
202 
203 signed __aeabi_idivmod(signed numerator, signed denominator)
204 {
205 	struct qr qr = { .q_n = 0, .r_n = 0 };
206 
207 	if (((numerator < 0) && (denominator > 0)) ||
208 	    ((numerator > 0) && (denominator < 0)))
209 		qr.q_n = 1;	/* quotient shall be negate */
210 	if (numerator < 0) {
211 		numerator = -numerator;
212 		qr.r_n = 1;	/* remainder shall be negate */
213 	}
214 	if (denominator < 0)
215 		denominator = -denominator;
216 
217 	uint_div_qr(numerator, denominator, &qr);
218 
219 	return ret_idivmod_values(qr.q, qr.r);
220 }
221