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