xref: /optee_os/lib/libutils/isoc/arch/arm/arm32_aeabi_softfloat.c (revision 78b7c7c7653f8bff42fe44d31a79d7f6bbfd4d47)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  * All rights reserved.
5  */
6 
7 #include <compiler.h>
8 #include "platform.h"
9 #include <softfloat.h>
10 
11 /*
12  * On ARM32 EABI defines both a soft-float ABI and a hard-float ABI,
13  * hard-float is basically a super set of soft-float. Hard-float requires
14  * all the support routines provided for soft-float, but the compiler may
15  * choose to optimize to not use some of them.
16  *
17  * The AEABI functions uses soft-float calling convention even if the
18  * functions are compiled for hard-float. So where float and double would
19  * have been expected we use aeabi_float_t and aeabi_double_t respectively
20  * instead.
21  */
22 typedef unsigned aeabi_float_t;
23 typedef unsigned long long aeabi_double_t;
24 
25 /*
26  * Helpers to convert between float32 and aeabi_float_t, and float64 and
27  * aeabi_double_t used by the AEABI functions below.
28  */
29 static aeabi_float_t f32_to_f(float32_t val)
30 {
31 	union {
32 		float32_t from;
33 		aeabi_float_t to;
34 	} res = { .from = val };
35 
36 	return res.to;
37 }
38 
39 static float32_t f32_from_f(aeabi_float_t val)
40 {
41 	union {
42 		aeabi_float_t from;
43 		float32_t to;
44 	} res = { .from = val };
45 
46 	return res.to;
47 }
48 
49 static aeabi_double_t f64_to_d(float64_t val)
50 {
51 	union {
52 		float64_t from;
53 		aeabi_double_t to;
54 	} res = { .from = val };
55 
56 	return res.to;
57 }
58 
59 static float64_t f64_from_d(aeabi_double_t val)
60 {
61 	union {
62 		aeabi_double_t from;
63 		float64_t to;
64 	} res = { .from = val };
65 
66 	return res.to;
67 }
68 
69 /*
70  * From ARM Run-time ABI for ARM Architecture
71  * ARM IHI 0043D, current through ABI release 2.09
72  *
73  * 4.1.2 The floating-point helper functions
74  */
75 
76 /*
77  * Table 2, Standard aeabi_double_t precision floating-point arithmetic helper
78  * functions
79  */
80 
81 aeabi_double_t __aeabi_dadd(aeabi_double_t a, aeabi_double_t b)
82 {
83 	return f64_to_d(f64_add(f64_from_d(a), f64_from_d(b)));
84 }
85 
86 aeabi_double_t __aeabi_ddiv(aeabi_double_t a, aeabi_double_t b)
87 {
88 	return f64_to_d(f64_div(f64_from_d(a), f64_from_d(b)));
89 }
90 
91 aeabi_double_t __aeabi_dmul(aeabi_double_t a, aeabi_double_t b)
92 {
93 	return f64_to_d(f64_mul(f64_from_d(a), f64_from_d(b)));
94 }
95 
96 
97 aeabi_double_t __aeabi_drsub(aeabi_double_t a, aeabi_double_t b)
98 {
99 	return f64_to_d(f64_sub(f64_from_d(b), f64_from_d(a)));
100 }
101 
102 aeabi_double_t __aeabi_dsub(aeabi_double_t a, aeabi_double_t b)
103 {
104 	return f64_to_d(f64_sub(f64_from_d(a), f64_from_d(b)));
105 }
106 
107 /*
108  * Table 3, double precision floating-point comparison helper functions
109  */
110 
111 int __aeabi_dcmpeq(aeabi_double_t a, aeabi_double_t b)
112 {
113 	return f64_eq(f64_from_d(a), f64_from_d(b));
114 }
115 
116 int __aeabi_dcmplt(aeabi_double_t a, aeabi_double_t b)
117 {
118 	return f64_lt(f64_from_d(a), f64_from_d(b));
119 }
120 
121 int __aeabi_dcmple(aeabi_double_t a, aeabi_double_t b)
122 {
123 	return f64_le(f64_from_d(a), f64_from_d(b));
124 }
125 
126 int __aeabi_dcmpge(aeabi_double_t a, aeabi_double_t b)
127 {
128 	return f64_le(f64_from_d(b), f64_from_d(a));
129 }
130 
131 int __aeabi_dcmpgt(aeabi_double_t a, aeabi_double_t b)
132 {
133 	return f64_lt(f64_from_d(b), f64_from_d(a));
134 }
135 
136 /*
137  * Table 4, Standard single precision floating-point arithmetic helper
138  * functions
139  */
140 
141 aeabi_float_t __aeabi_fadd(aeabi_float_t a, aeabi_float_t b)
142 {
143 	return f32_to_f(f32_add(f32_from_f(a), f32_from_f(b)));
144 }
145 
146 aeabi_float_t __aeabi_fdiv(aeabi_float_t a, aeabi_float_t b)
147 {
148 	return f32_to_f(f32_div(f32_from_f(a), f32_from_f(b)));
149 }
150 
151 aeabi_float_t __aeabi_fmul(aeabi_float_t a, aeabi_float_t b)
152 {
153 	return f32_to_f(f32_mul(f32_from_f(a), f32_from_f(b)));
154 }
155 
156 aeabi_float_t __aeabi_frsub(aeabi_float_t a, aeabi_float_t b)
157 {
158 	return f32_to_f(f32_sub(f32_from_f(b), f32_from_f(a)));
159 }
160 
161 aeabi_float_t __aeabi_fsub(aeabi_float_t a, aeabi_float_t b)
162 {
163 	return f32_to_f(f32_sub(f32_from_f(a), f32_from_f(b)));
164 }
165 
166 /*
167  * Table 5, Standard single precision floating-point comparison helper
168  * functions
169  */
170 
171 int __aeabi_fcmpeq(aeabi_float_t a, aeabi_float_t b)
172 {
173 	return f32_eq(f32_from_f(a), f32_from_f(b));
174 }
175 
176 int __aeabi_fcmplt(aeabi_float_t a, aeabi_float_t b)
177 {
178 	return f32_lt(f32_from_f(a), f32_from_f(b));
179 }
180 
181 int __aeabi_fcmple(aeabi_float_t a, aeabi_float_t b)
182 {
183 	return f32_le(f32_from_f(a), f32_from_f(b));
184 }
185 
186 int __aeabi_fcmpge(aeabi_float_t a, aeabi_float_t b)
187 {
188 	return f32_le(f32_from_f(b), f32_from_f(a));
189 }
190 
191 int __aeabi_fcmpgt(aeabi_float_t a, aeabi_float_t b)
192 {
193 	return f32_lt(f32_from_f(b), f32_from_f(a));
194 }
195 
196 /*
197  * Table 6, Standard floating-point to integer conversions
198  */
199 
200 int __aeabi_d2iz(aeabi_double_t a)
201 {
202 	return f64_to_i32_r_minMag(f64_from_d(a), false);
203 }
204 
205 unsigned __aeabi_d2uiz(aeabi_double_t a)
206 {
207 	return f64_to_ui32_r_minMag(f64_from_d(a), false);
208 }
209 
210 long long __aeabi_d2lz(aeabi_double_t a)
211 {
212 	return f64_to_i64_r_minMag(f64_from_d(a), false);
213 }
214 
215 unsigned long long __aeabi_d2ulz(aeabi_double_t a)
216 {
217 	return f64_to_ui64_r_minMag(f64_from_d(a), false);
218 }
219 
220 int __aeabi_f2iz(aeabi_float_t a)
221 {
222 	return f32_to_i32_r_minMag(f32_from_f(a), false);
223 }
224 
225 unsigned __aeabi_f2uiz(aeabi_float_t a)
226 {
227 	return f32_to_ui32_r_minMag(f32_from_f(a), false);
228 }
229 
230 long long __aeabi_f2lz(aeabi_float_t a)
231 {
232 	return f32_to_i64_r_minMag(f32_from_f(a), false);
233 }
234 
235 unsigned long long __aeabi_f2ulz(aeabi_float_t a)
236 {
237 	return f32_to_ui64_r_minMag(f32_from_f(a), false);
238 }
239 
240 /*
241  * Table 7, Standard conversions between floating types
242  */
243 
244 aeabi_float_t __aeabi_d2f(aeabi_double_t a)
245 {
246 	return f32_to_f(f64_to_f32(f64_from_d(a)));
247 }
248 
249 aeabi_double_t __aeabi_f2d(aeabi_float_t a)
250 {
251 	return f64_to_d(f32_to_f64(f32_from_f(a)));
252 }
253 
254 /*
255  * Table 8, Standard integer to floating-point conversions
256  */
257 
258 aeabi_double_t __aeabi_i2d(int a)
259 {
260 	return f64_to_d(i32_to_f64(a));
261 }
262 
263 aeabi_double_t __aeabi_ui2d(unsigned a)
264 {
265 	return f64_to_d(ui32_to_f64(a));
266 }
267 
268 aeabi_double_t __aeabi_l2d(long long a)
269 {
270 	return f64_to_d(i64_to_f64(a));
271 }
272 
273 aeabi_double_t __aeabi_ul2d(unsigned long long a)
274 {
275 	return f64_to_d(ui64_to_f64(a));
276 }
277 
278 aeabi_float_t __aeabi_i2f(int a)
279 {
280 	return f32_to_f(i32_to_f32(a));
281 }
282 
283 aeabi_float_t __aeabi_ui2f(unsigned a)
284 {
285 	return f32_to_f(ui32_to_f32(a));
286 }
287 
288 aeabi_float_t __aeabi_l2f(long long a)
289 {
290 	return f32_to_f(i64_to_f32(a));
291 }
292 
293 aeabi_float_t __aeabi_ul2f(unsigned long long a)
294 {
295 	return f32_to_f(ui64_to_f32(a));
296 }
297