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