1 /* Machine-dependent software floating-point definitions. 2 Sparc userland (_Q_*) version. 3 Copyright (C) 1997,1998,1999, 2002, 2006 Free Software Foundation, Inc. 4 This file is part of the GNU C Library. 5 Contributed by Richard Henderson (rth@cygnus.com), 6 Jakub Jelinek (jj@ultra.linux.cz) and 7 David S. Miller (davem@redhat.com). 8 9 The GNU C Library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2.1 of the License, or (at your option) any later version. 13 14 The GNU C Library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with the GNU C Library; if not, see 21 <http://www.gnu.org/licenses/>. */ 22 23 #include <fpu_control.h> 24 #include <stdlib.h> 25 26 #define _FP_W_TYPE_SIZE 32 27 #define _FP_W_TYPE unsigned long 28 #define _FP_WS_TYPE signed long 29 #define _FP_I_TYPE long 30 31 #define _FP_MUL_MEAT_S(R,X,Y) \ 32 _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) 33 #define _FP_MUL_MEAT_D(R,X,Y) \ 34 _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) 35 #define _FP_MUL_MEAT_Q(R,X,Y) \ 36 _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) 37 38 #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) 39 #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) 40 #define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) 41 42 #define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) 43 #define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 44 #define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 45 #define _FP_NANSIGN_S 0 46 #define _FP_NANSIGN_D 0 47 #define _FP_NANSIGN_Q 0 48 49 #define _FP_KEEPNANFRACP 1 50 51 /* If one NaN is signaling and the other is not, 52 * we choose that one, otherwise we choose X. 53 */ 54 /* For _Qp_* and _Q_*, this should prefer X, for 55 * CPU instruction emulation this should prefer Y. 56 * (see SPAMv9 B.2.2 section). 57 */ 58 #define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ 59 do { \ 60 if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ 61 && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \ 62 { \ 63 R##_s = Y##_s; \ 64 _FP_FRAC_COPY_##wc(R,Y); \ 65 } \ 66 else \ 67 { \ 68 R##_s = X##_s; \ 69 _FP_FRAC_COPY_##wc(R,X); \ 70 } \ 71 R##_c = FP_CLS_NAN; \ 72 } while (0) 73 74 /* Some assembly to speed things up. */ 75 #define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ 76 __asm__ ("addcc %r7,%8,%2\n\ 77 addxcc %r5,%6,%1\n\ 78 addx %r3,%4,%0" \ 79 : "=r" ((USItype)(r2)), \ 80 "=&r" ((USItype)(r1)), \ 81 "=&r" ((USItype)(r0)) \ 82 : "%rJ" ((USItype)(x2)), \ 83 "rI" ((USItype)(y2)), \ 84 "%rJ" ((USItype)(x1)), \ 85 "rI" ((USItype)(y1)), \ 86 "%rJ" ((USItype)(x0)), \ 87 "rI" ((USItype)(y0)) \ 88 : "cc") 89 90 #define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ 91 __asm__ ("subcc %r7,%8,%2\n\ 92 subxcc %r5,%6,%1\n\ 93 subx %r3,%4,%0" \ 94 : "=r" ((USItype)(r2)), \ 95 "=&r" ((USItype)(r1)), \ 96 "=&r" ((USItype)(r0)) \ 97 : "%rJ" ((USItype)(x2)), \ 98 "rI" ((USItype)(y2)), \ 99 "%rJ" ((USItype)(x1)), \ 100 "rI" ((USItype)(y1)), \ 101 "%rJ" ((USItype)(x0)), \ 102 "rI" ((USItype)(y0)) \ 103 : "cc") 104 105 #define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ 106 do { \ 107 /* We need to fool gcc, as we need to pass more than 10 \ 108 input/outputs. */ \ 109 register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \ 110 __asm__ __volatile__ ("\ 111 addcc %r8,%9,%1\n\ 112 addxcc %r6,%7,%0\n\ 113 addxcc %r4,%5,%%g2\n\ 114 addx %r2,%3,%%g1" \ 115 : "=&r" ((USItype)(r1)), \ 116 "=&r" ((USItype)(r0)) \ 117 : "%rJ" ((USItype)(x3)), \ 118 "rI" ((USItype)(y3)), \ 119 "%rJ" ((USItype)(x2)), \ 120 "rI" ((USItype)(y2)), \ 121 "%rJ" ((USItype)(x1)), \ 122 "rI" ((USItype)(y1)), \ 123 "%rJ" ((USItype)(x0)), \ 124 "rI" ((USItype)(y0)) \ 125 : "cc", "g1", "g2"); \ 126 __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \ 127 r3 = _t1; r2 = _t2; \ 128 } while (0) 129 130 #define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ 131 do { \ 132 /* We need to fool gcc, as we need to pass more than 10 \ 133 input/outputs. */ \ 134 register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \ 135 __asm__ __volatile__ ("\ 136 subcc %r8,%9,%1\n\ 137 subxcc %r6,%7,%0\n\ 138 subxcc %r4,%5,%%g2\n\ 139 subx %r2,%3,%%g1" \ 140 : "=&r" ((USItype)(r1)), \ 141 "=&r" ((USItype)(r0)) \ 142 : "%rJ" ((USItype)(x3)), \ 143 "rI" ((USItype)(y3)), \ 144 "%rJ" ((USItype)(x2)), \ 145 "rI" ((USItype)(y2)), \ 146 "%rJ" ((USItype)(x1)), \ 147 "rI" ((USItype)(y1)), \ 148 "%rJ" ((USItype)(x0)), \ 149 "rI" ((USItype)(y0)) \ 150 : "cc", "g1", "g2"); \ 151 __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \ 152 r3 = _t1; r2 = _t2; \ 153 } while (0) 154 155 #define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0) 156 157 #define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0) 158 159 #define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ 160 __asm__ ("addcc %3,%4,%3\n\ 161 addxcc %2,%%g0,%2\n\ 162 addxcc %1,%%g0,%1\n\ 163 addx %0,%%g0,%0" \ 164 : "=&r" ((USItype)(x3)), \ 165 "=&r" ((USItype)(x2)), \ 166 "=&r" ((USItype)(x1)), \ 167 "=&r" ((USItype)(x0)) \ 168 : "rI" ((USItype)(i)), \ 169 "0" ((USItype)(x3)), \ 170 "1" ((USItype)(x2)), \ 171 "2" ((USItype)(x1)), \ 172 "3" ((USItype)(x0)) \ 173 : "cc") 174 175 /* Obtain the current rounding mode. */ 176 #ifndef FP_ROUNDMODE 177 #define FP_ROUNDMODE ((_fcw >> 30) & 0x3) 178 #endif 179 180 /* Exception flags. */ 181 #define FP_EX_INVALID (1 << 4) 182 #define FP_EX_OVERFLOW (1 << 3) 183 #define FP_EX_UNDERFLOW (1 << 2) 184 #define FP_EX_DIVZERO (1 << 1) 185 #define FP_EX_INEXACT (1 << 0) 186 187 #define _FP_DECL_EX fpu_control_t _fcw 188 189 #ifdef __UCLIBC_HAS_FPU__ 190 #define FP_INIT_ROUNDMODE \ 191 do { \ 192 _FPU_GETCW(_fcw); \ 193 } while (0) 194 195 /* Simulate exceptions using double arithmetics. */ 196 extern double ___Q_simulate_exceptions(int exc); 197 198 #define FP_HANDLE_EXCEPTIONS \ 199 do { \ 200 if (!_fex) \ 201 { \ 202 /* This is the common case, so we do it inline. \ 203 * We need to clear cexc bits if any. \ 204 */ \ 205 extern unsigned long long ___Q_numbers[]; \ 206 __asm__ __volatile__("\ 207 ldd [%0], %%f30\n\ 208 faddd %%f30, %%f30, %%f30\ 209 " : : "r" (___Q_numbers) : "f30"); \ 210 } \ 211 else \ 212 ___Q_simulate_exceptions (_fex); \ 213 } while (0) 214 #endif 215