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