| /* | |
| * Copyright (c) 2015 - 2019, Linaro Limited | |
| * | |
| * SPDX-License-Identifier: BSD-2-Clause-Patent | |
| */ | |
| #include "platform.h" | |
| #include <softfloat.h> | |
| /* | |
| * On ARM32 EABI defines both a soft-float ABI and a hard-float ABI, | |
| * hard-float is basically a super set of soft-float. Hard-float requires | |
| * all the support routines provided for soft-float, but the compiler may | |
| * choose to optimize to not use some of them. | |
| * | |
| * The AEABI functions uses soft-float calling convention even if the | |
| * functions are compiled for hard-float. So where float and double would | |
| * have been expected we use aeabi_float_t and aeabi_double_t respectively | |
| * instead. | |
| */ | |
| typedef uint32_t aeabi_float_t; | |
| typedef uint64_t aeabi_double_t; | |
| /* | |
| * Helpers to convert between float32 and aeabi_float_t, and float64 and | |
| * aeabi_double_t used by the AEABI functions below. | |
| */ | |
| static aeabi_float_t | |
| f32_to_f ( | |
| float32_t val | |
| ) | |
| { | |
| return val.v; | |
| } | |
| static float32_t | |
| f32_from_f ( | |
| aeabi_float_t val | |
| ) | |
| { | |
| float32_t res; | |
| res.v = val; | |
| return res; | |
| } | |
| static aeabi_double_t | |
| f64_to_d ( | |
| float64_t val | |
| ) | |
| { | |
| return val.v; | |
| } | |
| static float64_t | |
| f64_from_d ( | |
| aeabi_double_t val | |
| ) | |
| { | |
| float64_t res; | |
| res.v = val; | |
| return res; | |
| } | |
| /* | |
| * From ARM Run-time ABI for ARM Architecture | |
| * ARM IHI 0043D, current through ABI release 2.09 | |
| * | |
| * 4.1.2 The floating-point helper functions | |
| */ | |
| /* | |
| * Table 2, Standard aeabi_double_t precision floating-point arithmetic helper | |
| * functions | |
| */ | |
| aeabi_double_t | |
| __aeabi_dadd ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_to_d (f64_add (f64_from_d (a), f64_from_d (b))); | |
| } | |
| aeabi_double_t | |
| __aeabi_ddiv ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_to_d (f64_div (f64_from_d (a), f64_from_d (b))); | |
| } | |
| aeabi_double_t | |
| __aeabi_dmul ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_to_d (f64_mul (f64_from_d (a), f64_from_d (b))); | |
| } | |
| aeabi_double_t | |
| __aeabi_drsub ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_to_d (f64_sub (f64_from_d (b), f64_from_d (a))); | |
| } | |
| aeabi_double_t | |
| __aeabi_dsub ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_to_d (f64_sub (f64_from_d (a), f64_from_d (b))); | |
| } | |
| /* | |
| * Table 3, double precision floating-point comparison helper functions | |
| */ | |
| int | |
| __aeabi_dcmpeq ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_eq (f64_from_d (a), f64_from_d (b)); | |
| } | |
| int | |
| __aeabi_dcmplt ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_lt (f64_from_d (a), f64_from_d (b)); | |
| } | |
| int | |
| __aeabi_dcmple ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_le (f64_from_d (a), f64_from_d (b)); | |
| } | |
| int | |
| __aeabi_dcmpge ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_le (f64_from_d (b), f64_from_d (a)); | |
| } | |
| int | |
| __aeabi_dcmpgt ( | |
| aeabi_double_t a, | |
| aeabi_double_t b | |
| ) | |
| { | |
| return f64_lt (f64_from_d (b), f64_from_d (a)); | |
| } | |
| /* | |
| * Table 4, Standard single precision floating-point arithmetic helper | |
| * functions | |
| */ | |
| aeabi_float_t | |
| __aeabi_fadd ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_to_f (f32_add (f32_from_f (a), f32_from_f (b))); | |
| } | |
| aeabi_float_t | |
| __aeabi_fdiv ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_to_f (f32_div (f32_from_f (a), f32_from_f (b))); | |
| } | |
| aeabi_float_t | |
| __aeabi_fmul ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_to_f (f32_mul (f32_from_f (a), f32_from_f (b))); | |
| } | |
| aeabi_float_t | |
| __aeabi_frsub ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_to_f (f32_sub (f32_from_f (b), f32_from_f (a))); | |
| } | |
| aeabi_float_t | |
| __aeabi_fsub ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_to_f (f32_sub (f32_from_f (a), f32_from_f (b))); | |
| } | |
| /* | |
| * Table 5, Standard single precision floating-point comparison helper | |
| * functions | |
| */ | |
| int | |
| __aeabi_fcmpeq ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_eq (f32_from_f (a), f32_from_f (b)); | |
| } | |
| int | |
| __aeabi_fcmplt ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_lt (f32_from_f (a), f32_from_f (b)); | |
| } | |
| int | |
| __aeabi_fcmple ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_le (f32_from_f (a), f32_from_f (b)); | |
| } | |
| int | |
| __aeabi_fcmpge ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_le (f32_from_f (b), f32_from_f (a)); | |
| } | |
| int | |
| __aeabi_fcmpgt ( | |
| aeabi_float_t a, | |
| aeabi_float_t b | |
| ) | |
| { | |
| return f32_lt (f32_from_f (b), f32_from_f (a)); | |
| } | |
| /* | |
| * Table 6, Standard floating-point to integer conversions | |
| */ | |
| int | |
| __aeabi_d2iz ( | |
| aeabi_double_t a | |
| ) | |
| { | |
| return f64_to_i32_r_minMag (f64_from_d (a), false); | |
| } | |
| unsigned | |
| __aeabi_d2uiz ( | |
| aeabi_double_t a | |
| ) | |
| { | |
| return f64_to_ui32_r_minMag (f64_from_d (a), false); | |
| } | |
| long long | |
| __aeabi_d2lz ( | |
| aeabi_double_t a | |
| ) | |
| { | |
| return f64_to_i64_r_minMag (f64_from_d (a), false); | |
| } | |
| unsigned long long | |
| __aeabi_d2ulz ( | |
| aeabi_double_t a | |
| ) | |
| { | |
| return f64_to_ui64_r_minMag (f64_from_d (a), false); | |
| } | |
| int | |
| __aeabi_f2iz ( | |
| aeabi_float_t a | |
| ) | |
| { | |
| return f32_to_i32_r_minMag (f32_from_f (a), false); | |
| } | |
| unsigned | |
| __aeabi_f2uiz ( | |
| aeabi_float_t a | |
| ) | |
| { | |
| return f32_to_ui32_r_minMag (f32_from_f (a), false); | |
| } | |
| long long | |
| __aeabi_f2lz ( | |
| aeabi_float_t a | |
| ) | |
| { | |
| return f32_to_i64_r_minMag (f32_from_f (a), false); | |
| } | |
| unsigned long long | |
| __aeabi_f2ulz ( | |
| aeabi_float_t a | |
| ) | |
| { | |
| return f32_to_ui64_r_minMag (f32_from_f (a), false); | |
| } | |
| /* | |
| * Table 7, Standard conversions between floating types | |
| */ | |
| aeabi_float_t | |
| __aeabi_d2f ( | |
| aeabi_double_t a | |
| ) | |
| { | |
| return f32_to_f (f64_to_f32 (f64_from_d (a))); | |
| } | |
| aeabi_double_t | |
| __aeabi_f2d ( | |
| aeabi_float_t a | |
| ) | |
| { | |
| return f64_to_d (f32_to_f64 (f32_from_f (a))); | |
| } | |
| /* | |
| * Table 8, Standard integer to floating-point conversions | |
| */ | |
| aeabi_double_t | |
| __aeabi_i2d ( | |
| int a | |
| ) | |
| { | |
| return f64_to_d (i32_to_f64 (a)); | |
| } | |
| aeabi_double_t | |
| __aeabi_ui2d ( | |
| unsigned a | |
| ) | |
| { | |
| return f64_to_d (ui32_to_f64 (a)); | |
| } | |
| aeabi_double_t | |
| __aeabi_l2d ( | |
| long long a | |
| ) | |
| { | |
| return f64_to_d (i64_to_f64 (a)); | |
| } | |
| aeabi_double_t | |
| __aeabi_ul2d ( | |
| unsigned long long a | |
| ) | |
| { | |
| return f64_to_d (ui64_to_f64 (a)); | |
| } | |
| aeabi_float_t | |
| __aeabi_i2f ( | |
| int a | |
| ) | |
| { | |
| return f32_to_f (i32_to_f32 (a)); | |
| } | |
| aeabi_float_t | |
| __aeabi_ui2f ( | |
| unsigned a | |
| ) | |
| { | |
| return f32_to_f (ui32_to_f32 (a)); | |
| } | |
| aeabi_float_t | |
| __aeabi_l2f ( | |
| long long a | |
| ) | |
| { | |
| return f32_to_f (i64_to_f32 (a)); | |
| } | |
| aeabi_float_t | |
| __aeabi_ul2f ( | |
| unsigned long long a | |
| ) | |
| { | |
| return f32_to_f (ui64_to_f32 (a)); | |
| } |