Emilio G. Cota | 3ac1f81 | 2018-03-08 21:09:40 -0500 | [diff] [blame] | 1 | /* |
| 2 | * In this file we wrap QEMU FP functions to look like softfloat/testfloat's, |
| 3 | * so that we can use the testfloat infrastructure as-is. |
| 4 | * |
| 5 | * This file must be included directly from fp-test.c. We could compile it |
| 6 | * separately, but it would be tedious to add declarations for all the wrappers. |
| 7 | */ |
| 8 | |
| 9 | static signed char sf_tininess_to_qemu(uint_fast8_t mode) |
| 10 | { |
| 11 | switch (mode) { |
| 12 | case softfloat_tininess_beforeRounding: |
| 13 | return float_tininess_before_rounding; |
| 14 | case softfloat_tininess_afterRounding: |
| 15 | return float_tininess_after_rounding; |
| 16 | default: |
| 17 | g_assert_not_reached(); |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | static signed char sf_rounding_to_qemu(uint_fast8_t mode) |
| 22 | { |
| 23 | switch (mode) { |
| 24 | case softfloat_round_near_even: |
| 25 | return float_round_nearest_even; |
| 26 | case softfloat_round_minMag: |
| 27 | return float_round_to_zero; |
| 28 | case softfloat_round_min: |
| 29 | return float_round_down; |
| 30 | case softfloat_round_max: |
| 31 | return float_round_up; |
| 32 | case softfloat_round_near_maxMag: |
| 33 | return float_round_ties_away; |
| 34 | case softfloat_round_odd: |
| 35 | return float_round_to_odd; |
| 36 | default: |
| 37 | g_assert_not_reached(); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | static uint_fast8_t qemu_flags_to_sf(uint8_t qflags) |
| 42 | { |
| 43 | uint_fast8_t ret = 0; |
| 44 | |
| 45 | if (qflags & float_flag_invalid) { |
| 46 | ret |= softfloat_flag_invalid; |
| 47 | } |
| 48 | if (qflags & float_flag_divbyzero) { |
| 49 | ret |= softfloat_flag_infinite; |
| 50 | } |
| 51 | if (qflags & float_flag_overflow) { |
| 52 | ret |= softfloat_flag_overflow; |
| 53 | } |
| 54 | if (qflags & float_flag_underflow) { |
| 55 | ret |= softfloat_flag_underflow; |
| 56 | } |
| 57 | if (qflags & float_flag_inexact) { |
| 58 | ret |= softfloat_flag_inexact; |
| 59 | } |
| 60 | return ret; |
| 61 | } |
| 62 | |
| 63 | /* |
| 64 | * floatx80 and float128 cannot be cast between qemu and softfloat, because |
| 65 | * in softfloat the order of the fields depends on the host's endianness. |
| 66 | */ |
| 67 | static extFloat80_t qemu_to_soft80(floatx80 a) |
| 68 | { |
| 69 | extFloat80_t ret; |
| 70 | |
| 71 | ret.signif = a.low; |
| 72 | ret.signExp = a.high; |
| 73 | return ret; |
| 74 | } |
| 75 | |
| 76 | static floatx80 soft_to_qemu80(extFloat80_t a) |
| 77 | { |
| 78 | floatx80 ret; |
| 79 | |
| 80 | ret.low = a.signif; |
| 81 | ret.high = a.signExp; |
| 82 | return ret; |
| 83 | } |
| 84 | |
| 85 | static float128_t qemu_to_soft128(float128 a) |
| 86 | { |
| 87 | float128_t ret; |
| 88 | struct uint128 *to = (struct uint128 *)&ret; |
| 89 | |
| 90 | to->v0 = a.low; |
| 91 | to->v64 = a.high; |
| 92 | return ret; |
| 93 | } |
| 94 | |
| 95 | static float128 soft_to_qemu128(float128_t a) |
| 96 | { |
| 97 | struct uint128 *from = (struct uint128 *)&a; |
| 98 | float128 ret; |
| 99 | |
| 100 | ret.low = from->v0; |
| 101 | ret.high = from->v64; |
| 102 | return ret; |
| 103 | } |
| 104 | |
| 105 | /* conversions */ |
| 106 | #define WRAP_SF_TO_SF_IEEE(name, func, a_type, b_type) \ |
| 107 | static b_type##_t name(a_type##_t a) \ |
| 108 | { \ |
| 109 | a_type *ap = (a_type *)&a; \ |
| 110 | b_type ret; \ |
| 111 | \ |
| 112 | ret = func(*ap, true, &qsf); \ |
| 113 | return *(b_type##_t *)&ret; \ |
| 114 | } |
| 115 | |
| 116 | WRAP_SF_TO_SF_IEEE(qemu_f16_to_f32, float16_to_float32, float16, float32) |
| 117 | WRAP_SF_TO_SF_IEEE(qemu_f16_to_f64, float16_to_float64, float16, float64) |
| 118 | |
| 119 | WRAP_SF_TO_SF_IEEE(qemu_f32_to_f16, float32_to_float16, float32, float16) |
| 120 | WRAP_SF_TO_SF_IEEE(qemu_f64_to_f16, float64_to_float16, float64, float16) |
| 121 | #undef WRAP_SF_TO_SF_IEEE |
| 122 | |
| 123 | #define WRAP_SF_TO_SF(name, func, a_type, b_type) \ |
| 124 | static b_type##_t name(a_type##_t a) \ |
| 125 | { \ |
| 126 | a_type *ap = (a_type *)&a; \ |
| 127 | b_type ret; \ |
| 128 | \ |
| 129 | ret = func(*ap, &qsf); \ |
| 130 | return *(b_type##_t *)&ret; \ |
| 131 | } |
| 132 | |
| 133 | WRAP_SF_TO_SF(qemu_f32_to_f64, float32_to_float64, float32, float64) |
| 134 | WRAP_SF_TO_SF(qemu_f64_to_f32, float64_to_float32, float64, float32) |
| 135 | #undef WRAP_SF_TO_SF |
| 136 | |
| 137 | #define WRAP_SF_TO_80(name, func, type) \ |
| 138 | static void name(type##_t a, extFloat80_t *res) \ |
| 139 | { \ |
| 140 | floatx80 ret; \ |
| 141 | type *ap = (type *)&a; \ |
| 142 | \ |
| 143 | ret = func(*ap, &qsf); \ |
| 144 | *res = qemu_to_soft80(ret); \ |
| 145 | } |
| 146 | |
| 147 | WRAP_SF_TO_80(qemu_f32_to_extF80M, float32_to_floatx80, float32) |
| 148 | WRAP_SF_TO_80(qemu_f64_to_extF80M, float64_to_floatx80, float64) |
| 149 | #undef WRAP_SF_TO_80 |
| 150 | |
| 151 | #define WRAP_SF_TO_128(name, func, type) \ |
| 152 | static void name(type##_t a, float128_t *res) \ |
| 153 | { \ |
| 154 | float128 ret; \ |
| 155 | type *ap = (type *)&a; \ |
| 156 | \ |
| 157 | ret = func(*ap, &qsf); \ |
| 158 | *res = qemu_to_soft128(ret); \ |
| 159 | } |
| 160 | |
| 161 | WRAP_SF_TO_128(qemu_f32_to_f128M, float32_to_float128, float32) |
| 162 | WRAP_SF_TO_128(qemu_f64_to_f128M, float64_to_float128, float64) |
| 163 | #undef WRAP_SF_TO_128 |
| 164 | |
| 165 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 166 | #define WRAP_SF_TO_INT(name, func, type, fast_type) \ |
| 167 | static fast_type name(type##_t a, uint_fast8_t round, bool exact) \ |
| 168 | { \ |
| 169 | type *ap = (type *)&a; \ |
| 170 | \ |
| 171 | qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ |
| 172 | return func(*ap, &qsf); \ |
| 173 | } |
| 174 | |
| 175 | WRAP_SF_TO_INT(qemu_f16_to_ui32, float16_to_uint32, float16, uint_fast32_t) |
| 176 | WRAP_SF_TO_INT(qemu_f16_to_ui64, float16_to_uint64, float16, uint_fast64_t) |
| 177 | |
| 178 | WRAP_SF_TO_INT(qemu_f32_to_ui32, float32_to_uint32, float32, uint_fast32_t) |
| 179 | WRAP_SF_TO_INT(qemu_f32_to_ui64, float32_to_uint64, float32, uint_fast64_t) |
| 180 | |
| 181 | WRAP_SF_TO_INT(qemu_f64_to_ui32, float64_to_uint32, float64, uint_fast32_t) |
| 182 | WRAP_SF_TO_INT(qemu_f64_to_ui64, float64_to_uint64, float64, uint_fast64_t) |
| 183 | |
| 184 | WRAP_SF_TO_INT(qemu_f16_to_i32, float16_to_int32, float16, int_fast32_t) |
| 185 | WRAP_SF_TO_INT(qemu_f16_to_i64, float16_to_int64, float16, int_fast64_t) |
| 186 | |
| 187 | WRAP_SF_TO_INT(qemu_f32_to_i32, float32_to_int32, float32, int_fast32_t) |
| 188 | WRAP_SF_TO_INT(qemu_f32_to_i64, float32_to_int64, float32, int_fast64_t) |
| 189 | |
| 190 | WRAP_SF_TO_INT(qemu_f64_to_i32, float64_to_int32, float64, int_fast32_t) |
| 191 | WRAP_SF_TO_INT(qemu_f64_to_i64, float64_to_int64, float64, int_fast64_t) |
| 192 | #undef WRAP_SF_TO_INT |
| 193 | |
| 194 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 195 | #define WRAP_SF_TO_INT_MINMAG(name, func, type, fast_type) \ |
| 196 | static fast_type name(type##_t a, bool exact) \ |
| 197 | { \ |
| 198 | type *ap = (type *)&a; \ |
| 199 | \ |
| 200 | return func(*ap, &qsf); \ |
| 201 | } |
| 202 | |
| 203 | WRAP_SF_TO_INT_MINMAG(qemu_f16_to_ui32_r_minMag, |
| 204 | float16_to_uint32_round_to_zero, float16, uint_fast32_t) |
| 205 | WRAP_SF_TO_INT_MINMAG(qemu_f16_to_ui64_r_minMag, |
| 206 | float16_to_uint64_round_to_zero, float16, uint_fast64_t) |
| 207 | |
| 208 | WRAP_SF_TO_INT_MINMAG(qemu_f16_to_i32_r_minMag, |
| 209 | float16_to_int32_round_to_zero, float16, int_fast32_t) |
| 210 | WRAP_SF_TO_INT_MINMAG(qemu_f16_to_i64_r_minMag, |
| 211 | float16_to_int64_round_to_zero, float16, int_fast64_t) |
| 212 | |
| 213 | WRAP_SF_TO_INT_MINMAG(qemu_f32_to_ui32_r_minMag, |
| 214 | float32_to_uint32_round_to_zero, float32, uint_fast32_t) |
| 215 | WRAP_SF_TO_INT_MINMAG(qemu_f32_to_ui64_r_minMag, |
| 216 | float32_to_uint64_round_to_zero, float32, uint_fast64_t) |
| 217 | |
| 218 | WRAP_SF_TO_INT_MINMAG(qemu_f32_to_i32_r_minMag, |
| 219 | float32_to_int32_round_to_zero, float32, int_fast32_t) |
| 220 | WRAP_SF_TO_INT_MINMAG(qemu_f32_to_i64_r_minMag, |
| 221 | float32_to_int64_round_to_zero, float32, int_fast64_t) |
| 222 | |
| 223 | WRAP_SF_TO_INT_MINMAG(qemu_f64_to_ui32_r_minMag, |
| 224 | float64_to_uint32_round_to_zero, float64, uint_fast32_t) |
| 225 | WRAP_SF_TO_INT_MINMAG(qemu_f64_to_ui64_r_minMag, |
| 226 | float64_to_uint64_round_to_zero, float64, uint_fast64_t) |
| 227 | |
| 228 | WRAP_SF_TO_INT_MINMAG(qemu_f64_to_i32_r_minMag, |
| 229 | float64_to_int32_round_to_zero, float64, int_fast32_t) |
| 230 | WRAP_SF_TO_INT_MINMAG(qemu_f64_to_i64_r_minMag, |
| 231 | float64_to_int64_round_to_zero, float64, int_fast64_t) |
| 232 | #undef WRAP_SF_TO_INT_MINMAG |
| 233 | |
| 234 | #define WRAP_80_TO_SF(name, func, type) \ |
| 235 | static type##_t name(const extFloat80_t *ap) \ |
| 236 | { \ |
| 237 | floatx80 a; \ |
| 238 | type ret; \ |
| 239 | \ |
| 240 | a = soft_to_qemu80(*ap); \ |
| 241 | ret = func(a, &qsf); \ |
| 242 | return *(type##_t *)&ret; \ |
| 243 | } |
| 244 | |
| 245 | WRAP_80_TO_SF(qemu_extF80M_to_f32, floatx80_to_float32, float32) |
| 246 | WRAP_80_TO_SF(qemu_extF80M_to_f64, floatx80_to_float64, float64) |
| 247 | #undef WRAP_80_TO_SF |
| 248 | |
| 249 | #define WRAP_128_TO_SF(name, func, type) \ |
| 250 | static type##_t name(const float128_t *ap) \ |
| 251 | { \ |
| 252 | float128 a; \ |
| 253 | type ret; \ |
| 254 | \ |
| 255 | a = soft_to_qemu128(*ap); \ |
| 256 | ret = func(a, &qsf); \ |
| 257 | return *(type##_t *)&ret; \ |
| 258 | } |
| 259 | |
| 260 | WRAP_128_TO_SF(qemu_f128M_to_f32, float128_to_float32, float32) |
| 261 | WRAP_128_TO_SF(qemu_f128M_to_f64, float128_to_float64, float64) |
| 262 | #undef WRAP_128_TO_SF |
| 263 | |
| 264 | static void qemu_extF80M_to_f128M(const extFloat80_t *from, float128_t *to) |
| 265 | { |
| 266 | floatx80 qfrom; |
| 267 | float128 qto; |
| 268 | |
| 269 | qfrom = soft_to_qemu80(*from); |
| 270 | qto = floatx80_to_float128(qfrom, &qsf); |
| 271 | *to = qemu_to_soft128(qto); |
| 272 | } |
| 273 | |
| 274 | static void qemu_f128M_to_extF80M(const float128_t *from, extFloat80_t *to) |
| 275 | { |
| 276 | float128 qfrom; |
| 277 | floatx80 qto; |
| 278 | |
| 279 | qfrom = soft_to_qemu128(*from); |
| 280 | qto = float128_to_floatx80(qfrom, &qsf); |
| 281 | *to = qemu_to_soft80(qto); |
| 282 | } |
| 283 | |
| 284 | #define WRAP_INT_TO_SF(name, func, int_type, type) \ |
| 285 | static type##_t name(int_type a) \ |
| 286 | { \ |
| 287 | type ret; \ |
| 288 | \ |
| 289 | ret = func(a, &qsf); \ |
| 290 | return *(type##_t *)&ret; \ |
| 291 | } |
| 292 | |
| 293 | WRAP_INT_TO_SF(qemu_ui32_to_f16, uint32_to_float16, uint32_t, float16) |
| 294 | WRAP_INT_TO_SF(qemu_ui32_to_f32, uint32_to_float32, uint32_t, float32) |
| 295 | WRAP_INT_TO_SF(qemu_ui32_to_f64, uint32_to_float64, uint32_t, float64) |
| 296 | |
| 297 | WRAP_INT_TO_SF(qemu_ui64_to_f16, uint64_to_float16, uint64_t, float16) |
| 298 | WRAP_INT_TO_SF(qemu_ui64_to_f32, uint64_to_float32, uint64_t, float32) |
| 299 | WRAP_INT_TO_SF(qemu_ui64_to_f64, uint64_to_float64, uint64_t, float64) |
| 300 | |
| 301 | WRAP_INT_TO_SF(qemu_i32_to_f16, int32_to_float16, int32_t, float16) |
| 302 | WRAP_INT_TO_SF(qemu_i32_to_f32, int32_to_float32, int32_t, float32) |
| 303 | WRAP_INT_TO_SF(qemu_i32_to_f64, int32_to_float64, int32_t, float64) |
| 304 | |
| 305 | WRAP_INT_TO_SF(qemu_i64_to_f16, int64_to_float16, int64_t, float16) |
| 306 | WRAP_INT_TO_SF(qemu_i64_to_f32, int64_to_float32, int64_t, float32) |
| 307 | WRAP_INT_TO_SF(qemu_i64_to_f64, int64_to_float64, int64_t, float64) |
| 308 | #undef WRAP_INT_TO_SF |
| 309 | |
| 310 | #define WRAP_INT_TO_80(name, func, int_type) \ |
| 311 | static void name(int_type a, extFloat80_t *res) \ |
| 312 | { \ |
| 313 | floatx80 ret; \ |
| 314 | \ |
| 315 | ret = func(a, &qsf); \ |
| 316 | *res = qemu_to_soft80(ret); \ |
| 317 | } |
| 318 | |
| 319 | WRAP_INT_TO_80(qemu_i32_to_extF80M, int32_to_floatx80, int32_t) |
| 320 | WRAP_INT_TO_80(qemu_i64_to_extF80M, int64_to_floatx80, int64_t) |
| 321 | #undef WRAP_INT_TO_80 |
| 322 | |
| 323 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 324 | #define WRAP_80_TO_INT(name, func, fast_type) \ |
| 325 | static fast_type name(const extFloat80_t *ap, uint_fast8_t round, \ |
| 326 | bool exact) \ |
| 327 | { \ |
| 328 | floatx80 a; \ |
| 329 | \ |
| 330 | a = soft_to_qemu80(*ap); \ |
| 331 | qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ |
| 332 | return func(a, &qsf); \ |
| 333 | } |
| 334 | |
| 335 | WRAP_80_TO_INT(qemu_extF80M_to_i32, floatx80_to_int32, int_fast32_t) |
| 336 | WRAP_80_TO_INT(qemu_extF80M_to_i64, floatx80_to_int64, int_fast64_t) |
| 337 | #undef WRAP_80_TO_INT |
| 338 | |
| 339 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 340 | #define WRAP_80_TO_INT_MINMAG(name, func, fast_type) \ |
| 341 | static fast_type name(const extFloat80_t *ap, bool exact) \ |
| 342 | { \ |
| 343 | floatx80 a; \ |
| 344 | \ |
| 345 | a = soft_to_qemu80(*ap); \ |
| 346 | return func(a, &qsf); \ |
| 347 | } |
| 348 | |
| 349 | WRAP_80_TO_INT_MINMAG(qemu_extF80M_to_i32_r_minMag, |
| 350 | floatx80_to_int32_round_to_zero, int_fast32_t) |
| 351 | WRAP_80_TO_INT_MINMAG(qemu_extF80M_to_i64_r_minMag, |
| 352 | floatx80_to_int64_round_to_zero, int_fast64_t) |
| 353 | #undef WRAP_80_TO_INT_MINMAG |
| 354 | |
| 355 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 356 | #define WRAP_128_TO_INT(name, func, fast_type) \ |
| 357 | static fast_type name(const float128_t *ap, uint_fast8_t round, \ |
| 358 | bool exact) \ |
| 359 | { \ |
| 360 | float128 a; \ |
| 361 | \ |
| 362 | a = soft_to_qemu128(*ap); \ |
| 363 | qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ |
| 364 | return func(a, &qsf); \ |
| 365 | } |
| 366 | |
| 367 | WRAP_128_TO_INT(qemu_f128M_to_i32, float128_to_int32, int_fast32_t) |
| 368 | WRAP_128_TO_INT(qemu_f128M_to_i64, float128_to_int64, int_fast64_t) |
| 369 | |
Alex Bennée | 80d491f | 2019-02-06 14:31:40 +0000 | [diff] [blame] | 370 | WRAP_128_TO_INT(qemu_f128M_to_ui32, float128_to_uint32, uint_fast32_t) |
Emilio G. Cota | 3ac1f81 | 2018-03-08 21:09:40 -0500 | [diff] [blame] | 371 | WRAP_128_TO_INT(qemu_f128M_to_ui64, float128_to_uint64, uint_fast64_t) |
| 372 | #undef WRAP_128_TO_INT |
| 373 | |
| 374 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 375 | #define WRAP_128_TO_INT_MINMAG(name, func, fast_type) \ |
| 376 | static fast_type name(const float128_t *ap, bool exact) \ |
| 377 | { \ |
| 378 | float128 a; \ |
| 379 | \ |
| 380 | a = soft_to_qemu128(*ap); \ |
| 381 | return func(a, &qsf); \ |
| 382 | } |
| 383 | |
| 384 | WRAP_128_TO_INT_MINMAG(qemu_f128M_to_i32_r_minMag, |
| 385 | float128_to_int32_round_to_zero, int_fast32_t) |
| 386 | WRAP_128_TO_INT_MINMAG(qemu_f128M_to_i64_r_minMag, |
| 387 | float128_to_int64_round_to_zero, int_fast64_t) |
| 388 | |
| 389 | WRAP_128_TO_INT_MINMAG(qemu_f128M_to_ui32_r_minMag, |
| 390 | float128_to_uint32_round_to_zero, uint_fast32_t) |
| 391 | WRAP_128_TO_INT_MINMAG(qemu_f128M_to_ui64_r_minMag, |
| 392 | float128_to_uint64_round_to_zero, uint_fast64_t) |
| 393 | #undef WRAP_128_TO_INT_MINMAG |
| 394 | |
| 395 | #define WRAP_INT_TO_128(name, func, int_type) \ |
| 396 | static void name(int_type a, float128_t *res) \ |
| 397 | { \ |
| 398 | float128 ret; \ |
| 399 | \ |
| 400 | ret = func(a, &qsf); \ |
| 401 | *res = qemu_to_soft128(ret); \ |
| 402 | } |
| 403 | |
| 404 | WRAP_INT_TO_128(qemu_ui64_to_f128M, uint64_to_float128, uint64_t) |
| 405 | |
| 406 | WRAP_INT_TO_128(qemu_i32_to_f128M, int32_to_float128, int32_t) |
| 407 | WRAP_INT_TO_128(qemu_i64_to_f128M, int64_to_float128, int64_t) |
| 408 | #undef WRAP_INT_TO_128 |
| 409 | |
| 410 | /* Note: exact is ignored since qemu's softfloat assumes it is set */ |
| 411 | #define WRAP_ROUND_TO_INT(name, func, type) \ |
| 412 | static type##_t name(type##_t a, uint_fast8_t round, bool exact) \ |
| 413 | { \ |
| 414 | type *ap = (type *)&a; \ |
| 415 | type ret; \ |
| 416 | \ |
| 417 | qsf.float_rounding_mode = sf_rounding_to_qemu(round); \ |
| 418 | ret = func(*ap, &qsf); \ |
| 419 | return *(type##_t *)&ret; \ |
| 420 | } |
| 421 | |
| 422 | WRAP_ROUND_TO_INT(qemu_f16_roundToInt, float16_round_to_int, float16) |
| 423 | WRAP_ROUND_TO_INT(qemu_f32_roundToInt, float32_round_to_int, float32) |
| 424 | WRAP_ROUND_TO_INT(qemu_f64_roundToInt, float64_round_to_int, float64) |
| 425 | #undef WRAP_ROUND_TO_INT |
| 426 | |
| 427 | static void qemu_extF80M_roundToInt(const extFloat80_t *ap, uint_fast8_t round, |
| 428 | bool exact, extFloat80_t *res) |
| 429 | { |
| 430 | floatx80 a; |
| 431 | floatx80 ret; |
| 432 | |
| 433 | a = soft_to_qemu80(*ap); |
| 434 | qsf.float_rounding_mode = sf_rounding_to_qemu(round); |
| 435 | ret = floatx80_round_to_int(a, &qsf); |
| 436 | *res = qemu_to_soft80(ret); |
| 437 | } |
| 438 | |
| 439 | static void qemu_f128M_roundToInt(const float128_t *ap, uint_fast8_t round, |
| 440 | bool exact, float128_t *res) |
| 441 | { |
| 442 | float128 a; |
| 443 | float128 ret; |
| 444 | |
| 445 | a = soft_to_qemu128(*ap); |
| 446 | qsf.float_rounding_mode = sf_rounding_to_qemu(round); |
| 447 | ret = float128_round_to_int(a, &qsf); |
| 448 | *res = qemu_to_soft128(ret); |
| 449 | } |
| 450 | |
| 451 | /* operations */ |
| 452 | #define WRAP1(name, func, type) \ |
| 453 | static type##_t name(type##_t a) \ |
| 454 | { \ |
| 455 | type *ap = (type *)&a; \ |
| 456 | type ret; \ |
| 457 | \ |
| 458 | ret = func(*ap, &qsf); \ |
| 459 | return *(type##_t *)&ret; \ |
| 460 | } |
| 461 | |
| 462 | #define WRAP2(name, func, type) \ |
| 463 | static type##_t name(type##_t a, type##_t b) \ |
| 464 | { \ |
| 465 | type *ap = (type *)&a; \ |
| 466 | type *bp = (type *)&b; \ |
| 467 | type ret; \ |
| 468 | \ |
| 469 | ret = func(*ap, *bp, &qsf); \ |
| 470 | return *(type##_t *)&ret; \ |
| 471 | } |
| 472 | |
| 473 | #define WRAP_COMMON_OPS(b) \ |
| 474 | WRAP1(qemu_f##b##_sqrt, float##b##_sqrt, float##b) \ |
| 475 | WRAP2(qemu_f##b##_add, float##b##_add, float##b) \ |
| 476 | WRAP2(qemu_f##b##_sub, float##b##_sub, float##b) \ |
| 477 | WRAP2(qemu_f##b##_mul, float##b##_mul, float##b) \ |
| 478 | WRAP2(qemu_f##b##_div, float##b##_div, float##b) |
| 479 | |
| 480 | WRAP_COMMON_OPS(16) |
| 481 | WRAP_COMMON_OPS(32) |
| 482 | WRAP_COMMON_OPS(64) |
| 483 | #undef WRAP_COMMON |
| 484 | |
| 485 | WRAP2(qemu_f32_rem, float32_rem, float32) |
| 486 | WRAP2(qemu_f64_rem, float64_rem, float64) |
| 487 | #undef WRAP2 |
| 488 | #undef WRAP1 |
| 489 | |
| 490 | #define WRAP1_80(name, func) \ |
| 491 | static void name(const extFloat80_t *ap, extFloat80_t *res) \ |
| 492 | { \ |
| 493 | floatx80 a; \ |
| 494 | floatx80 ret; \ |
| 495 | \ |
| 496 | a = soft_to_qemu80(*ap); \ |
| 497 | ret = func(a, &qsf); \ |
| 498 | *res = qemu_to_soft80(ret); \ |
| 499 | } |
| 500 | |
| 501 | WRAP1_80(qemu_extF80M_sqrt, floatx80_sqrt) |
| 502 | #undef WRAP1_80 |
| 503 | |
| 504 | #define WRAP1_128(name, func) \ |
| 505 | static void name(const float128_t *ap, float128_t *res) \ |
| 506 | { \ |
| 507 | float128 a; \ |
| 508 | float128 ret; \ |
| 509 | \ |
| 510 | a = soft_to_qemu128(*ap); \ |
| 511 | ret = func(a, &qsf); \ |
| 512 | *res = qemu_to_soft128(ret); \ |
| 513 | } |
| 514 | |
| 515 | WRAP1_128(qemu_f128M_sqrt, float128_sqrt) |
| 516 | #undef WRAP1_128 |
| 517 | |
| 518 | #define WRAP2_80(name, func) \ |
| 519 | static void name(const extFloat80_t *ap, const extFloat80_t *bp, \ |
| 520 | extFloat80_t *res) \ |
| 521 | { \ |
| 522 | floatx80 a; \ |
| 523 | floatx80 b; \ |
| 524 | floatx80 ret; \ |
| 525 | \ |
| 526 | a = soft_to_qemu80(*ap); \ |
| 527 | b = soft_to_qemu80(*bp); \ |
| 528 | ret = func(a, b, &qsf); \ |
| 529 | *res = qemu_to_soft80(ret); \ |
| 530 | } |
| 531 | |
| 532 | WRAP2_80(qemu_extF80M_add, floatx80_add) |
| 533 | WRAP2_80(qemu_extF80M_sub, floatx80_sub) |
| 534 | WRAP2_80(qemu_extF80M_mul, floatx80_mul) |
| 535 | WRAP2_80(qemu_extF80M_div, floatx80_div) |
| 536 | WRAP2_80(qemu_extF80M_rem, floatx80_rem) |
| 537 | #undef WRAP2_80 |
| 538 | |
| 539 | #define WRAP2_128(name, func) \ |
| 540 | static void name(const float128_t *ap, const float128_t *bp, \ |
| 541 | float128_t *res) \ |
| 542 | { \ |
| 543 | float128 a; \ |
| 544 | float128 b; \ |
| 545 | float128 ret; \ |
| 546 | \ |
| 547 | a = soft_to_qemu128(*ap); \ |
| 548 | b = soft_to_qemu128(*bp); \ |
| 549 | ret = func(a, b, &qsf); \ |
| 550 | *res = qemu_to_soft128(ret); \ |
| 551 | } |
| 552 | |
| 553 | WRAP2_128(qemu_f128M_add, float128_add) |
| 554 | WRAP2_128(qemu_f128M_sub, float128_sub) |
| 555 | WRAP2_128(qemu_f128M_mul, float128_mul) |
| 556 | WRAP2_128(qemu_f128M_div, float128_div) |
| 557 | WRAP2_128(qemu_f128M_rem, float128_rem) |
| 558 | #undef WRAP2_128 |
| 559 | |
| 560 | #define WRAP_MULADD(name, func, type) \ |
| 561 | static type##_t name(type##_t a, type##_t b, type##_t c) \ |
| 562 | { \ |
| 563 | type *ap = (type *)&a; \ |
| 564 | type *bp = (type *)&b; \ |
| 565 | type *cp = (type *)&c; \ |
| 566 | type ret; \ |
| 567 | \ |
| 568 | ret = func(*ap, *bp, *cp, 0, &qsf); \ |
| 569 | return *(type##_t *)&ret; \ |
| 570 | } |
| 571 | |
| 572 | WRAP_MULADD(qemu_f16_mulAdd, float16_muladd, float16) |
| 573 | WRAP_MULADD(qemu_f32_mulAdd, float32_muladd, float32) |
| 574 | WRAP_MULADD(qemu_f64_mulAdd, float64_muladd, float64) |
| 575 | #undef WRAP_MULADD |
| 576 | |
Richard Henderson | dedd123 | 2020-10-24 06:04:19 -0700 | [diff] [blame] | 577 | static void qemu_f128M_mulAdd(const float128_t *ap, const float128_t *bp, |
| 578 | const float128_t *cp, float128_t *res) |
| 579 | { |
| 580 | float128 a, b, c, ret; |
| 581 | |
| 582 | a = soft_to_qemu128(*ap); |
| 583 | b = soft_to_qemu128(*bp); |
| 584 | c = soft_to_qemu128(*cp); |
| 585 | ret = float128_muladd(a, b, c, 0, &qsf); |
| 586 | *res = qemu_to_soft128(ret); |
| 587 | } |
| 588 | |
Emilio G. Cota | 3ac1f81 | 2018-03-08 21:09:40 -0500 | [diff] [blame] | 589 | #define WRAP_CMP16(name, func, retcond) \ |
| 590 | static bool name(float16_t a, float16_t b) \ |
| 591 | { \ |
| 592 | float16 *ap = (float16 *)&a; \ |
| 593 | float16 *bp = (float16 *)&b; \ |
| 594 | int ret; \ |
| 595 | \ |
| 596 | ret = func(*ap, *bp, &qsf); \ |
| 597 | return retcond; \ |
| 598 | } |
| 599 | |
| 600 | WRAP_CMP16(qemu_f16_eq_signaling, float16_compare, ret == 0) |
| 601 | WRAP_CMP16(qemu_f16_eq, float16_compare_quiet, ret == 0) |
| 602 | WRAP_CMP16(qemu_f16_le, float16_compare, ret <= 0) |
| 603 | WRAP_CMP16(qemu_f16_lt, float16_compare, ret < 0) |
| 604 | WRAP_CMP16(qemu_f16_le_quiet, float16_compare_quiet, ret <= 0) |
| 605 | WRAP_CMP16(qemu_f16_lt_quiet, float16_compare_quiet, ret < 0) |
| 606 | #undef WRAP_CMP16 |
| 607 | |
| 608 | #define WRAP_CMP(name, func, type) \ |
| 609 | static bool name(type##_t a, type##_t b) \ |
| 610 | { \ |
| 611 | type *ap = (type *)&a; \ |
| 612 | type *bp = (type *)&b; \ |
| 613 | \ |
| 614 | return !!func(*ap, *bp, &qsf); \ |
| 615 | } |
| 616 | |
| 617 | #define GEN_WRAP_CMP(b) \ |
| 618 | WRAP_CMP(qemu_f##b##_eq_signaling, float##b##_eq, float##b) \ |
| 619 | WRAP_CMP(qemu_f##b##_eq, float##b##_eq_quiet, float##b) \ |
| 620 | WRAP_CMP(qemu_f##b##_le, float##b##_le, float##b) \ |
| 621 | WRAP_CMP(qemu_f##b##_lt, float##b##_lt, float##b) \ |
| 622 | WRAP_CMP(qemu_f##b##_le_quiet, float##b##_le_quiet, float##b) \ |
| 623 | WRAP_CMP(qemu_f##b##_lt_quiet, float##b##_lt_quiet, float##b) |
| 624 | |
| 625 | GEN_WRAP_CMP(32) |
| 626 | GEN_WRAP_CMP(64) |
| 627 | #undef GEN_WRAP_CMP |
| 628 | #undef WRAP_CMP |
| 629 | |
| 630 | #define WRAP_CMP80(name, func) \ |
| 631 | static bool name(const extFloat80_t *ap, const extFloat80_t *bp) \ |
| 632 | { \ |
| 633 | floatx80 a; \ |
| 634 | floatx80 b; \ |
| 635 | \ |
| 636 | a = soft_to_qemu80(*ap); \ |
| 637 | b = soft_to_qemu80(*bp); \ |
| 638 | return !!func(a, b, &qsf); \ |
| 639 | } |
| 640 | |
| 641 | WRAP_CMP80(qemu_extF80M_eq_signaling, floatx80_eq) |
| 642 | WRAP_CMP80(qemu_extF80M_eq, floatx80_eq_quiet) |
| 643 | WRAP_CMP80(qemu_extF80M_le, floatx80_le) |
| 644 | WRAP_CMP80(qemu_extF80M_lt, floatx80_lt) |
| 645 | WRAP_CMP80(qemu_extF80M_le_quiet, floatx80_le_quiet) |
Alex Bennée | 90d0045 | 2021-05-11 19:47:49 -0500 | [diff] [blame] | 646 | WRAP_CMP80(qemu_extF80M_lt_quiet, floatx80_lt_quiet) |
Emilio G. Cota | 3ac1f81 | 2018-03-08 21:09:40 -0500 | [diff] [blame] | 647 | #undef WRAP_CMP80 |
| 648 | |
| 649 | #define WRAP_CMP128(name, func) \ |
| 650 | static bool name(const float128_t *ap, const float128_t *bp) \ |
| 651 | { \ |
| 652 | float128 a; \ |
| 653 | float128 b; \ |
| 654 | \ |
| 655 | a = soft_to_qemu128(*ap); \ |
| 656 | b = soft_to_qemu128(*bp); \ |
| 657 | return !!func(a, b, &qsf); \ |
| 658 | } |
| 659 | |
| 660 | WRAP_CMP128(qemu_f128M_eq_signaling, float128_eq) |
| 661 | WRAP_CMP128(qemu_f128M_eq, float128_eq_quiet) |
| 662 | WRAP_CMP128(qemu_f128M_le, float128_le) |
| 663 | WRAP_CMP128(qemu_f128M_lt, float128_lt) |
| 664 | WRAP_CMP128(qemu_f128M_le_quiet, float128_le_quiet) |
| 665 | WRAP_CMP128(qemu_f128M_lt_quiet, float128_lt_quiet) |
| 666 | #undef WRAP_CMP128 |