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