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