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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 199 int __aeabi_d2iz(aeabi_double_t a) 200 { 201 return f64_to_i32_r_minMag(f64_from_d(a), false); 202 } 203 204 unsigned __aeabi_d2uiz(aeabi_double_t a) 205 { 206 return f64_to_ui32_r_minMag(f64_from_d(a), false); 207 } 208 209 long long __aeabi_d2lz(aeabi_double_t a) 210 { 211 return f64_to_i64_r_minMag(f64_from_d(a), false); 212 } 213 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 219 int __aeabi_f2iz(aeabi_float_t a) 220 { 221 return f32_to_i32_r_minMag(f32_from_f(a), false); 222 } 223 224 unsigned __aeabi_f2uiz(aeabi_float_t a) 225 { 226 return f32_to_ui32_r_minMag(f32_from_f(a), false); 227 } 228 229 long long __aeabi_f2lz(aeabi_float_t a) 230 { 231 return f32_to_i64_r_minMag(f32_from_f(a), false); 232 } 233 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 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 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 257 aeabi_double_t __aeabi_i2d(int a) 258 { 259 return f64_to_d(i32_to_f64(a)); 260 } 261 262 aeabi_double_t __aeabi_ui2d(unsigned a) 263 { 264 return f64_to_d(ui32_to_f64(a)); 265 } 266 267 aeabi_double_t __aeabi_l2d(long long a) 268 { 269 return f64_to_d(i64_to_f64(a)); 270 } 271 272 aeabi_double_t __aeabi_ul2d(unsigned long long a) 273 { 274 return f64_to_d(ui64_to_f64(a)); 275 } 276 277 aeabi_float_t __aeabi_i2f(int a) 278 { 279 return f32_to_f(i32_to_f32(a)); 280 } 281 282 aeabi_float_t __aeabi_ui2f(unsigned a) 283 { 284 return f32_to_f(ui32_to_f32(a)); 285 } 286 287 aeabi_float_t __aeabi_l2f(long long a) 288 { 289 return f32_to_f(i64_to_f32(a)); 290 } 291 292 aeabi_float_t __aeabi_ul2f(unsigned long long a) 293 { 294 return f32_to_f(ui64_to_f32(a)); 295 } 296