1 /* $NetBSD: qp.c,v 1.1 2014/08/10 05:47:37 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 33 #include "milieu.h" 34 #include "softfloat.h" 35 36 /* 37 * This file provides wrappers for the softfloat functions. We can't use 38 * invoke them directly since long double arguments are passed in FP/SIMD 39 * as well as being returned in them while float128 arguments are passed 40 * in normal registers. 41 */ 42 43 long double __addtf3(long double, long double); 44 long double __divtf3(long double, long double); 45 long double __modtf3(long double, long double); 46 long double __multf3(long double, long double); 47 long double __negtf2(long double); 48 long double __subtf3(long double, long double); 49 50 int __getf2(long double, long double); 51 int __lttf2(long double, long double); 52 int __gttf2(long double, long double); 53 int __letf2(long double, long double); 54 int __eqtf2(long double, long double); 55 int __netf2(long double, long double); 56 int __unordtf2(long double, long double); 57 58 double __trunctfdf2(long double); 59 float __trunctfsf2(long double); 60 61 long double __extendsftf2(float); 62 long double __extenddftf2(double); 63 64 long double __floatsitf(int32_t); 65 long double __floatditf(int64_t); 66 67 long double __floatunsitf(uint32_t); 68 long double __floatunditf(uint64_t); 69 70 int32_t __fixtfsi(long double); 71 int64_t __fixtfdi(long double); 72 73 uint32_t __fixuntfsi(long double); 74 uint64_t __fixuntfdi(long double); 75 76 #if 0 77 long double __floattitf(int128_t); 78 long double __floatuntitf(uint128_t); 79 int128_t __fixtfti(long double); 80 uint128_t __fixuntfti(long double); 81 #endif 82 83 union sf_ieee_flt_u { 84 float fltu_f; 85 float32 fltu_f32; 86 }; 87 88 union sf_ieee_dbl_u { 89 double dblu_d; 90 float64 dblu_f64; 91 }; 92 93 union sf_ieee_ldbl_u { 94 long double ldblu_ld; 95 float128 ldblu_f128; 96 }; 97 98 long double 99 __addtf3(long double ld_a, long double ld_b) 100 { 101 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 102 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 103 const union sf_ieee_ldbl_u c = { 104 .ldblu_f128 = float128_add(a.ldblu_f128, b.ldblu_f128) 105 }; 106 107 return c.ldblu_ld; 108 } 109 110 long double 111 __divtf3(long double ld_a, long double ld_b) 112 { 113 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 114 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 115 const union sf_ieee_ldbl_u c = { 116 .ldblu_f128 = float128_div(a.ldblu_f128, b.ldblu_f128) 117 }; 118 119 return c.ldblu_ld; 120 } 121 122 long double 123 __multf3(long double ld_a, long double ld_b) 124 { 125 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 126 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 127 const union sf_ieee_ldbl_u c = { 128 .ldblu_f128 = float128_mul(a.ldblu_f128, b.ldblu_f128) 129 }; 130 131 return c.ldblu_ld; 132 } 133 134 long double 135 __negtf2(long double ld_a) 136 { 137 const union sf_ieee_ldbl_u zero = { .ldblu_ld = 0.0 }; 138 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 139 const union sf_ieee_ldbl_u b = { 140 .ldblu_f128 = float128_div(zero.ldblu_f128, a.ldblu_f128) 141 }; 142 143 return b.ldblu_ld; 144 } 145 146 long double 147 __subtf3(long double ld_a, long double ld_b) 148 { 149 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 150 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 151 const union sf_ieee_ldbl_u c = { 152 .ldblu_f128 = float128_sub(a.ldblu_f128, b.ldblu_f128) 153 }; 154 155 return c.ldblu_ld; 156 } 157 158 #if 0 159 int 160 __cmptf3(float128 *a, float128 *b) 161 { 162 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 163 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 164 165 if (float128_eq(*a, *b)) 166 return 0; 167 168 if (float128_le(*a, *b)) 169 return 1; 170 171 return 2; 172 } 173 174 175 /* 176 * XXX 177 */ 178 int 179 _Qp_cmpe(float128 *a, float128 *b) 180 { 181 return _Qp_cmp(a, b); 182 } 183 #endif 184 185 int 186 __eqtf2(long double ld_a, long double ld_b) 187 { 188 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 189 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 190 191 return float128_eq(a.ldblu_f128, b.ldblu_f128); 192 } 193 194 int 195 __getf2(long double ld_a, long double ld_b) 196 { 197 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 198 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 199 200 return float128_le(b.ldblu_f128, a.ldblu_f128); 201 } 202 203 int 204 __gttf2(long double ld_a, long double ld_b) 205 { 206 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 207 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 208 209 return float128_lt(b.ldblu_f128, a.ldblu_f128); 210 } 211 212 int 213 __letf2(long double ld_a, long double ld_b) 214 { 215 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 216 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 217 218 return float128_le(a.ldblu_f128, b.ldblu_f128); 219 } 220 221 int 222 __lttf2(long double ld_a, long double ld_b) 223 { 224 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 225 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 226 227 return float128_lt(a.ldblu_f128, b.ldblu_f128); 228 } 229 230 int 231 __netf2(long double ld_a, long double ld_b) 232 { 233 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 234 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 235 236 return !float128_eq(a.ldblu_f128, b.ldblu_f128); 237 } 238 239 float 240 __trunctfsf2(long double ld_a) 241 { 242 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 243 const union sf_ieee_flt_u c = { 244 .fltu_f32 = float128_to_float32(a.ldblu_f128), 245 }; 246 247 return c.fltu_f; 248 } 249 250 double 251 __trunctfdf2(long double ld_a) 252 { 253 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 254 const union sf_ieee_dbl_u c = { 255 .dblu_f64 = float128_to_float64(a.ldblu_f128), 256 }; 257 258 return c.dblu_d; 259 } 260 261 int32_t 262 __fixtfsi(long double ld_a) 263 { 264 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 265 return float128_to_int32_round_to_zero(a.ldblu_f128); 266 } 267 268 int64_t 269 __fixtfdi(long double ld_a) 270 { 271 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 272 273 return float128_to_int64_round_to_zero(a.ldblu_f128); 274 } 275 276 #if 0 277 uint32_t 278 __fixuntfsi(long double ld_a) 279 { 280 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 281 282 return float128_to_uint32_round_to_zero(a.ldblu_f128); 283 } 284 285 uint64_t 286 __fixuntfdi(long double ld_a) 287 { 288 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 289 290 return float128_to_uint64_round_to_zero(a.ldblu_f128); 291 } 292 #endif 293 294 long double 295 __extendsftf2(float f_a) 296 { 297 const union sf_ieee_flt_u a = { .fltu_f = f_a }; 298 const union sf_ieee_ldbl_u c = { 299 .ldblu_f128 = float32_to_float128(a.fltu_f32) 300 }; 301 302 return c.ldblu_ld; 303 } 304 305 long double 306 __extenddftf2(double d_a) 307 { 308 const union sf_ieee_dbl_u a = { .dblu_d = d_a }; 309 const union sf_ieee_ldbl_u c = { 310 .ldblu_f128 = float64_to_float128(a.dblu_f64) 311 }; 312 313 return c.ldblu_ld; 314 } 315 316 long double 317 __floatunsitf(uint32_t a) 318 { 319 const union sf_ieee_ldbl_u c = { 320 .ldblu_f128 = int64_to_float128(a) 321 }; 322 323 return c.ldblu_ld; 324 } 325 326 long double 327 __floatunditf(uint64_t a) 328 { 329 union sf_ieee_ldbl_u c; 330 const uint64_t msb64 = 1LL << 63; 331 332 if (a & msb64) { 333 static const union sf_ieee_ldbl_u two63 = { 334 .ldblu_ld = 0x1.0p63 335 }; 336 337 c.ldblu_f128 = int64_to_float128(a ^ msb64); 338 c.ldblu_f128 = float128_add(c.ldblu_f128, two63.ldblu_f128); 339 } else { 340 c.ldblu_f128 = int64_to_float128(a); 341 } 342 return c.ldblu_ld; 343 } 344 345 long double 346 __floatsitf(int32_t a) 347 { 348 const union sf_ieee_ldbl_u c = { 349 .ldblu_f128 = int64_to_float128(a) 350 }; 351 352 return c.ldblu_ld; 353 } 354 355 long double 356 __floatditf(int64_t a) 357 { 358 const union sf_ieee_ldbl_u c = { 359 .ldblu_f128 = int64_to_float128(a) 360 }; 361 362 return c.ldblu_ld; 363 } 364 365 int 366 __unordtf2(long double ld_a, long double ld_b) 367 { 368 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a }; 369 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b }; 370 371 /* 372 * The comparison is unordered if either input is a NaN. 373 * Test for this by comparing each operand with itself. 374 * We must perform both comparisons to correctly check for 375 * signalling NaNs. 376 */ 377 return 1 ^ (float128_eq(a.ldblu_f128, a.ldblu_f128) & float128_eq(b.ldblu_f128, b.ldblu_f128)); 378 } 379