1f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar/* Implementations for copysign, ilogb, and nextafter for float16 based on 2f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * corresponding float32 implementations in 3f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * bionic/libm/upstream-freebsd/lib/msun/src 4f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar */ 5f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 6f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar/* 7f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * ==================================================== 8f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 9f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * 10f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * Developed at SunPro, a Sun Microsystems, Inc. business. 11f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * Permission to use, copy, modify, and distribute this 12f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * software is freely granted, provided that this notice 13f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * is preserved. 14f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar * ==================================================== 15f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar */ 16f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 17f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar#include "rs_core.rsh" 18f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar#include "rs_f16_util.h" 19f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 20f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_copysignf.c 21f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainarextern half __attribute__((overloadable)) copysign(half x, half y) { 22f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar short hx, hy; 23f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar GET_HALF_WORD(hx, x); 24f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar GET_HALF_WORD(hy, y); 25f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 26a53bf64187bcf01ed1c62eacd52f6c6f41b5864bPirama Arumuga Nainar SET_HALF_WORD(x, (hx & 0x7fff) | (hy & 0x8000)); 27f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return x; 28f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar} 29f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 30884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_frexpf.c 31884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainarextern half __attribute__((overloadable)) frexp(half x, int *eptr) { 32884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar short hx, ix; 33884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar static const half two12 = 4096; 34884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar 35884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar GET_HALF_WORD(hx, x); 36884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar ix = hx & 0x7fff; 37884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar 38884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar *eptr = 0; 39884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar if (ix >= 0x7c00 || ix == 0) return x; // NaN, infinity or zero 40884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar if (ix <= 0x0400) { 41884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar // x is subnormal. Scale it by 2^12 (and adjust eptr accordingly) so 42884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar // that even the smallest subnormal value becomes normal. 43884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar x *= two12; 44884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar GET_HALF_WORD(hx, x); 45884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar ix = hx & 0x7fff; 46884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar *eptr = -12; 47884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 48884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar 49884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar // Adjust eptr by (non-biased exponent of hx + 1). Set the non-biased 50884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar // exponent to be equal to -1 so that abs(hx) is between 0.5 and 1. 51884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar *eptr += (ix >> 10) - 14; 52884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar hx = (hx & 0x83ff) | 0x3800; 53884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar SET_HALF_WORD(x, hx); 54884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar return x; 55884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar} 56884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar 57f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_ilogbf.c 58f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainarextern int __attribute__((overloadable)) ilogb(half x) { 59f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar const int RS_INT_MAX = 0x7fffffff; 60f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar const int RS_INT_MIN = 0x80000000; 61f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 62f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar short hx, ix; 63f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar GET_HALF_WORD(hx, x); 64f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar hx &= 0x7fff; 65f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 66f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (hx < 0x0400) { // subnormal 67f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (hx == 0) 68f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return RS_INT_MIN; // for zero 69f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar for (hx <<= 5, ix = -14; hx > 0; hx <<= 1) 70f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar ix -= 1; 71f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return ix; 72f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar } 73f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar else if (hx < 0x7c00) { 74f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return (hx >> 10) - 15; 75f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar } 76f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar else { // hx >= 0x7c00 77f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return RS_INT_MAX; // for NaN and infinity 78f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar } 79f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar} 80f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 81884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_modff.c 82884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainarextern half __attribute__((overloadable)) modf(half x, half *iptr) { 83884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar short i0, j0; 84884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar unsigned short i; 85884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar GET_HALF_WORD(i0, x); 86884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar j0 = ((i0 >> 10) & 0x1f) - 15; // exponent of x 87884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar if (j0 < 10) { 88884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar if (j0 < 0) { // No integral part 89884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar SET_HALF_WORD(*iptr, i0 & 0x8000); // *iptr = +/- 0 90884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar return x; 91884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 92884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar else { 93884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar i = 0x03ff >> j0; // mask to check fractional parts of x 94884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar if ((i0 & i) == 0) { // no bits set in fractional part 95884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar *iptr = x; 96884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar SET_HALF_WORD(x, i0 & 0x8000); 97884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar return x; 98884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 99884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar else { 100884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar SET_HALF_WORD(*iptr, i0 & ~i); // zero out fractional parts 101884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar return x - *iptr; 102884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 103884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 104884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 105884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar else { // No fractional part 106884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar unsigned short ix; 107884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar *iptr = x; 108884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar if (x != x) 109884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar return x; 110884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar GET_HALF_WORD(ix, x); 111884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar SET_HALF_WORD(x, ix & 0x8000); // x = +/- 0 112884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar return x; 113884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar } 114884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar} 115884bc7c83f113a25b82e66ca45b1c6839b97666fPirama Arumuga Nainar 116f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_nextafterf.c 117f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainarextern half __attribute__((overloadable)) nextafter(half x, half y) { 118f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar volatile half t; 119f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar short hx, hy, ix, iy; 120f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 121f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar GET_HALF_WORD(hx, x); 122f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar GET_HALF_WORD(hy, y); 123f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar ix = hx & 0x7fff; // |x| 124f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar iy = hy & 0x7fff; // |y| 125f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 126f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if ((ix > 0x7c00) || // x is nan 127f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar (iy > 0x7c00)) // y is nan 128f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return x + y; // return nan 129f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 130f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (x == y) return y; // x == y. return y 131f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (ix == 0) { 132f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar SET_HALF_WORD(x, (hy & 0x8000) | 1); 133f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return x; 134f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar } 135f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 136f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (hx >= 0) { // x >= 0 137f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (hx > hy) 138f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar hx -= 1; // x > y, x -= 1 ulp 139f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar else 140f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar hx += 1; // x < y, x += 1 ulp 141f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar } 142f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar else { // x < 0 143f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar if (hy>= 0 || hx > hy) 144f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar hx -= 1; // x < y, x -= 1 ulp 145f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar else 146f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar hx += 1; 147f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar } 148f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar 149f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar SET_HALF_WORD(x, hx); 150f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar return x; 151f9760483073d9f452e4701fbf367dc518f7e6531Pirama Arumuga Nainar} 152