qp.c revision 1.1.24.1 1 /* $NetBSD: qp.c,v 1.1.24.1 2018/09/06 06:55:19 pgoyette 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 double __trunctfdf2(long double);
51 float __trunctfsf2(long double);
52
53 long double __extendsftf2(float);
54 long double __extenddftf2(double);
55
56 long double __floatsitf(int32_t);
57 long double __floatditf(int64_t);
58
59 long double __floatunsitf(uint32_t);
60 long double __floatunditf(uint64_t);
61
62 int32_t __fixtfsi(long double);
63 int64_t __fixtfdi(long double);
64
65 uint32_t __fixuntfsi(long double);
66 uint64_t __fixuntfdi(long double);
67
68 #if 0
69 long double __floattitf(int128_t);
70 long double __floatuntitf(uint128_t);
71 int128_t __fixtfti(long double);
72 uint128_t __fixuntfti(long double);
73 #endif
74
75 union sf_ieee_flt_u {
76 float fltu_f;
77 float32 fltu_f32;
78 };
79
80 union sf_ieee_dbl_u {
81 double dblu_d;
82 float64 dblu_f64;
83 };
84
85 union sf_ieee_ldbl_u {
86 long double ldblu_ld;
87 float128 ldblu_f128;
88 };
89
90 long double
91 __addtf3(long double ld_a, long double ld_b)
92 {
93 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
94 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b };
95 const union sf_ieee_ldbl_u c = {
96 .ldblu_f128 = float128_add(a.ldblu_f128, b.ldblu_f128)
97 };
98
99 return c.ldblu_ld;
100 }
101
102 long double
103 __divtf3(long double ld_a, long double ld_b)
104 {
105 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
106 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b };
107 const union sf_ieee_ldbl_u c = {
108 .ldblu_f128 = float128_div(a.ldblu_f128, b.ldblu_f128)
109 };
110
111 return c.ldblu_ld;
112 }
113
114 long double
115 __multf3(long double ld_a, long double ld_b)
116 {
117 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
118 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b };
119 const union sf_ieee_ldbl_u c = {
120 .ldblu_f128 = float128_mul(a.ldblu_f128, b.ldblu_f128)
121 };
122
123 return c.ldblu_ld;
124 }
125
126 long double
127 __negtf2(long double ld_a)
128 {
129 const union sf_ieee_ldbl_u zero = { .ldblu_ld = 0.0 };
130 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
131 const union sf_ieee_ldbl_u b = {
132 .ldblu_f128 = float128_div(zero.ldblu_f128, a.ldblu_f128)
133 };
134
135 return b.ldblu_ld;
136 }
137
138 long double
139 __subtf3(long double ld_a, long double ld_b)
140 {
141 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
142 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b };
143 const union sf_ieee_ldbl_u c = {
144 .ldblu_f128 = float128_sub(a.ldblu_f128, b.ldblu_f128)
145 };
146
147 return c.ldblu_ld;
148 }
149
150 #if 0
151 int
152 __cmptf3(float128 *a, float128 *b)
153 {
154 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
155 const union sf_ieee_ldbl_u b = { .ldblu_ld = ld_b };
156
157 if (float128_eq(*a, *b))
158 return 0;
159
160 if (float128_le(*a, *b))
161 return 1;
162
163 return 2;
164 }
165
166
167 /*
168 * XXX
169 */
170 int
171 _Qp_cmpe(float128 *a, float128 *b)
172 {
173 return _Qp_cmp(a, b);
174 }
175 #endif
176
177 float
178 __trunctfsf2(long double ld_a)
179 {
180 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
181 const union sf_ieee_flt_u c = {
182 .fltu_f32 = float128_to_float32(a.ldblu_f128),
183 };
184
185 return c.fltu_f;
186 }
187
188 double
189 __trunctfdf2(long double ld_a)
190 {
191 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
192 const union sf_ieee_dbl_u c = {
193 .dblu_f64 = float128_to_float64(a.ldblu_f128),
194 };
195
196 return c.dblu_d;
197 }
198
199 int32_t
200 __fixtfsi(long double ld_a)
201 {
202 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
203 return float128_to_int32_round_to_zero(a.ldblu_f128);
204 }
205
206 int64_t
207 __fixtfdi(long double ld_a)
208 {
209 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
210
211 return float128_to_int64_round_to_zero(a.ldblu_f128);
212 }
213
214 #if 0
215 uint32_t
216 __fixuntfsi(long double ld_a)
217 {
218 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
219
220 return float128_to_uint32_round_to_zero(a.ldblu_f128);
221 }
222
223 uint64_t
224 __fixuntfdi(long double ld_a)
225 {
226 const union sf_ieee_ldbl_u a = { .ldblu_ld = ld_a };
227
228 return float128_to_uint64_round_to_zero(a.ldblu_f128);
229 }
230 #endif
231
232 long double
233 __extendsftf2(float f_a)
234 {
235 const union sf_ieee_flt_u a = { .fltu_f = f_a };
236 const union sf_ieee_ldbl_u c = {
237 .ldblu_f128 = float32_to_float128(a.fltu_f32)
238 };
239
240 return c.ldblu_ld;
241 }
242
243 long double
244 __extenddftf2(double d_a)
245 {
246 const union sf_ieee_dbl_u a = { .dblu_d = d_a };
247 const union sf_ieee_ldbl_u c = {
248 .ldblu_f128 = float64_to_float128(a.dblu_f64)
249 };
250
251 return c.ldblu_ld;
252 }
253
254 long double
255 __floatunsitf(uint32_t a)
256 {
257 const union sf_ieee_ldbl_u c = {
258 .ldblu_f128 = int64_to_float128(a)
259 };
260
261 return c.ldblu_ld;
262 }
263
264 long double
265 __floatunditf(uint64_t a)
266 {
267 union sf_ieee_ldbl_u c;
268 const uint64_t msb64 = 1LL << 63;
269
270 if (a & msb64) {
271 static const union sf_ieee_ldbl_u two63 = {
272 .ldblu_ld = 0x1.0p63
273 };
274
275 c.ldblu_f128 = int64_to_float128(a ^ msb64);
276 c.ldblu_f128 = float128_add(c.ldblu_f128, two63.ldblu_f128);
277 } else {
278 c.ldblu_f128 = int64_to_float128(a);
279 }
280 return c.ldblu_ld;
281 }
282
283 long double
284 __floatsitf(int32_t a)
285 {
286 const union sf_ieee_ldbl_u c = {
287 .ldblu_f128 = int64_to_float128(a)
288 };
289
290 return c.ldblu_ld;
291 }
292
293 long double
294 __floatditf(int64_t a)
295 {
296 const union sf_ieee_ldbl_u c = {
297 .ldblu_f128 = int64_to_float128(a)
298 };
299
300 return c.ldblu_ld;
301 }
302