Target FP: Remove unused floating-point routines
[deliverable/binutils-gdb.git] / gdb / target-float.c
CommitLineData
70100014
UW
1/* Floating point routines for GDB, the GNU debugger.
2
3 Copyright (C) 2017 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "dfp.h"
22#include "doublest.h"
23#include "gdbtypes.h"
24#include "floatformat.h"
25#include "target-float.h"
26
27
50637b26
UW
28/* Helper routines operating on binary floating-point data. */
29
66c02b9e
UW
30#include <math.h>
31
50637b26
UW
32/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
33 to an integer value (rounding towards zero). */
34static LONGEST
35floatformat_to_longest (const struct floatformat *fmt, const gdb_byte *addr)
36{
37 DOUBLEST d;
38 floatformat_to_doublest (fmt, addr, &d);
39 return (LONGEST) d;
40}
41
42/* Convert signed integer VAL to a target floating-number of format FMT
43 and store it as byte-stream ADDR. */
44static void
45floatformat_from_longest (const struct floatformat *fmt, gdb_byte *addr,
46 LONGEST val)
47{
48 DOUBLEST d = (DOUBLEST) val;
49 floatformat_from_doublest (fmt, &d, addr);
50}
51
52/* Convert unsigned integer VAL to a target floating-number of format FMT
53 and store it as byte-stream ADDR. */
54static void
55floatformat_from_ulongest (const struct floatformat *fmt, gdb_byte *addr,
56 ULONGEST val)
57{
58 DOUBLEST d = (DOUBLEST) val;
59 floatformat_from_doublest (fmt, &d, addr);
60}
61
14ad9311
UW
62/* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
63 to a floating-point value in the host "double" format. */
64static double
65floatformat_to_host_double (const struct floatformat *fmt,
66 const gdb_byte *addr)
67{
68 DOUBLEST d;
69 floatformat_to_doublest (fmt, addr, &d);
70 return (double) d;
71}
72
73/* Convert floating-point value VAL in the host "double" format to a target
74 floating-number of format FMT and store it as byte-stream ADDR. */
75static void
76floatformat_from_host_double (const struct floatformat *fmt, gdb_byte *addr,
77 double val)
78{
79 DOUBLEST d = (DOUBLEST) val;
80 floatformat_from_doublest (fmt, &d, addr);
81}
82
50637b26
UW
83/* Convert a floating-point number of format FROM_FMT from the target
84 byte-stream FROM to a floating-point number of format TO_FMT, and
85 store it to the target byte-stream TO. */
86static void
87floatformat_convert (const gdb_byte *from, const struct floatformat *from_fmt,
88 gdb_byte *to, const struct floatformat *to_fmt)
89{
90 if (from_fmt == to_fmt)
91 {
92 /* The floating-point formats match, so we simply copy the data. */
93 memcpy (to, from, floatformat_totalsize_bytes (to_fmt));
94 }
95 else
96 {
97 /* The floating-point formats don't match. The best we can do
98 (apart from simulating the target FPU) is converting to the
99 widest floating-point type supported by the host, and then
100 again to the desired type. */
101 DOUBLEST d;
102
103 floatformat_to_doublest (from_fmt, from, &d);
104 floatformat_from_doublest (to_fmt, &d, to);
105 }
106}
107
66c02b9e
UW
108/* Perform the binary operation indicated by OPCODE, using as operands the
109 target byte streams X and Y, interpreted as floating-point numbers of
110 formats FMT_X and FMT_Y, respectively. Convert the result to format
111 FMT_RES and store it into the byte-stream RES. */
112static void
113floatformat_binop (enum exp_opcode op,
114 const struct floatformat *fmt_x, const gdb_byte *x,
115 const struct floatformat *fmt_y, const gdb_byte *y,
116 const struct floatformat *fmt_result, gdb_byte *result)
117{
118 DOUBLEST v1, v2, v = 0;
119
120 floatformat_to_doublest (fmt_x, x, &v1);
121 floatformat_to_doublest (fmt_y, y, &v2);
122
123 switch (op)
124 {
125 case BINOP_ADD:
126 v = v1 + v2;
127 break;
128
129 case BINOP_SUB:
130 v = v1 - v2;
131 break;
132
133 case BINOP_MUL:
134 v = v1 * v2;
135 break;
136
137 case BINOP_DIV:
138 v = v1 / v2;
139 break;
140
141 case BINOP_EXP:
142 errno = 0;
143 v = pow (v1, v2);
144 if (errno)
145 error (_("Cannot perform exponentiation: %s"),
146 safe_strerror (errno));
147 break;
148
149 case BINOP_MIN:
150 v = v1 < v2 ? v1 : v2;
151 break;
152
153 case BINOP_MAX:
154 v = v1 > v2 ? v1 : v2;
155 break;
156
157 default:
158 error (_("Integer-only operation on floating point number."));
159 break;
160 }
161
162 floatformat_from_doublest (fmt_result, &v, result);
163}
164
165/* Compare the two target byte streams X and Y, interpreted as floating-point
166 numbers of formats FMT_X and FMT_Y, respectively. Return zero if X and Y
167 are equal, -1 if X is less than Y, and 1 otherwise. */
168static int
169floatformat_compare (const struct floatformat *fmt_x, const gdb_byte *x,
170 const struct floatformat *fmt_y, const gdb_byte *y)
171{
172 DOUBLEST v1, v2;
173
174 floatformat_to_doublest (fmt_x, x, &v1);
175 floatformat_to_doublest (fmt_y, y, &v2);
176
177 if (v1 == v2)
178 return 0;
179 if (v1 < v2)
180 return -1;
181 return 1;
182}
183
50637b26 184
70100014
UW
185/* Typed floating-point routines. These routines operate on floating-point
186 values in target format, represented by a byte buffer interpreted as a
187 "struct type", which may be either a binary or decimal floating-point
188 type (TYPE_CODE_FLT or TYPE_CODE_DECFLOAT). */
189
190/* Return whether the byte-stream ADDR holds a valid value of
191 floating-point type TYPE. */
192bool
193target_float_is_valid (const gdb_byte *addr, const struct type *type)
194{
195 if (TYPE_CODE (type) == TYPE_CODE_FLT)
196 return floatformat_is_valid (floatformat_from_type (type), addr);
197
198 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
199 return true;
200
201 gdb_assert_not_reached ("unexpected type code");
202}
203
204/* Return whether the byte-stream ADDR, interpreted as floating-point
205 type TYPE, is numerically equal to zero (of either sign). */
206bool
207target_float_is_zero (const gdb_byte *addr, const struct type *type)
208{
209 if (TYPE_CODE (type) == TYPE_CODE_FLT)
210 return (floatformat_classify (floatformat_from_type (type), addr)
211 == float_zero);
212
213 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
214 return decimal_is_zero (addr, TYPE_LENGTH (type),
215 gdbarch_byte_order (get_type_arch (type)));
216
217 gdb_assert_not_reached ("unexpected type code");
218}
219
f69fdf9b
UW
220/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
221 to a string, optionally using the print format FORMAT. */
222std::string
223target_float_to_string (const gdb_byte *addr, const struct type *type,
224 const char *format)
225{
226 if (TYPE_CODE (type) == TYPE_CODE_FLT)
227 return floatformat_to_string (floatformat_from_type (type), addr, format);
228
229 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
230 return decimal_to_string (addr, TYPE_LENGTH (type),
231 gdbarch_byte_order (get_type_arch (type)),
232 format);
233
234 gdb_assert_not_reached ("unexpected type code");
235}
236
237/* Parse string STRING into a target floating-number of type TYPE and
238 store it as byte-stream ADDR. Return whether parsing succeeded. */
239bool
240target_float_from_string (gdb_byte *addr, const struct type *type,
241 const std::string &string)
242{
243 /* Ensure possible padding bytes in the target buffer are zeroed out. */
244 memset (addr, 0, TYPE_LENGTH (type));
245
246 if (TYPE_CODE (type) == TYPE_CODE_FLT)
247 return floatformat_from_string (floatformat_from_type (type), addr,
248 string);
249
250 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
251 return decimal_from_string (addr, TYPE_LENGTH (type),
252 gdbarch_byte_order (get_type_arch (type)),
253 string);
254
255 gdb_assert_not_reached ("unexpected type code");
256}
50637b26
UW
257
258/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
259 to an integer value (rounding towards zero). */
260LONGEST
261target_float_to_longest (const gdb_byte *addr, const struct type *type)
262{
263 if (TYPE_CODE (type) == TYPE_CODE_FLT)
264 return floatformat_to_longest (floatformat_from_type (type), addr);
265
266 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
267 return decimal_to_longest (addr, TYPE_LENGTH (type),
268 gdbarch_byte_order (get_type_arch (type)));
269
270 gdb_assert_not_reached ("unexpected type code");
271}
272
273/* Convert signed integer VAL to a target floating-number of type TYPE
274 and store it as byte-stream ADDR. */
275void
276target_float_from_longest (gdb_byte *addr, const struct type *type,
277 LONGEST val)
278{
279 /* Ensure possible padding bytes in the target buffer are zeroed out. */
280 memset (addr, 0, TYPE_LENGTH (type));
281
282 if (TYPE_CODE (type) == TYPE_CODE_FLT)
283 {
284 floatformat_from_longest (floatformat_from_type (type), addr, val);
285 return;
286 }
287
288 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
289 {
290 decimal_from_longest (val, addr, TYPE_LENGTH (type),
291 gdbarch_byte_order (get_type_arch (type)));
292 return;
293 }
294
295 gdb_assert_not_reached ("unexpected type code");
296}
297
298/* Convert unsigned integer VAL to a target floating-number of type TYPE
299 and store it as byte-stream ADDR. */
300void
301target_float_from_ulongest (gdb_byte *addr, const struct type *type,
302 ULONGEST val)
303{
304 /* Ensure possible padding bytes in the target buffer are zeroed out. */
305 memset (addr, 0, TYPE_LENGTH (type));
306
307 if (TYPE_CODE (type) == TYPE_CODE_FLT)
308 {
309 floatformat_from_ulongest (floatformat_from_type (type), addr, val);
310 return;
311 }
312
313 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
314 {
315 decimal_from_ulongest (val, addr, TYPE_LENGTH (type),
316 gdbarch_byte_order (get_type_arch (type)));
317 return;
318 }
319
320 gdb_assert_not_reached ("unexpected type code");
321}
322
14ad9311
UW
323/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
324 to a floating-point value in the host "double" format. */
325double
326target_float_to_host_double (const gdb_byte *addr,
327 const struct type *type)
328{
329 if (TYPE_CODE (type) == TYPE_CODE_FLT)
330 return floatformat_to_host_double (floatformat_from_type (type), addr);
331
332 /* We don't support conversions between target decimal floating-point
333 types and the host double type here. */
334
335 gdb_assert_not_reached ("unexpected type code");
336}
337
338/* Convert floating-point value VAL in the host "double" format to a target
339 floating-number of type TYPE and store it as byte-stream ADDR. */
340void
341target_float_from_host_double (gdb_byte *addr, const struct type *type,
342 double val)
343{
344 /* Ensure possible padding bytes in the target buffer are zeroed out. */
345 memset (addr, 0, TYPE_LENGTH (type));
346
347 if (TYPE_CODE (type) == TYPE_CODE_FLT)
348 {
349 floatformat_from_host_double (floatformat_from_type (type), addr, val);
350 return;
351 }
352
353 /* We don't support conversions between target decimal floating-point
354 types and the host double type here. */
355
356 gdb_assert_not_reached ("unexpected type code");
357}
358
50637b26
UW
359/* Convert a floating-point number of type FROM_TYPE from the target
360 byte-stream FROM to a floating-point number of type TO_TYPE, and
361 store it to the target byte-stream TO. */
362void
363target_float_convert (const gdb_byte *from, const struct type *from_type,
364 gdb_byte *to, const struct type *to_type)
365{
366 /* Ensure possible padding bytes in the target buffer are zeroed out. */
367 memset (to, 0, TYPE_LENGTH (to_type));
368
369 /* Use direct conversion routines if we have them. */
370
371 if (TYPE_CODE (from_type) == TYPE_CODE_FLT
372 && TYPE_CODE (to_type) == TYPE_CODE_FLT)
373 {
374 floatformat_convert (from, floatformat_from_type (from_type),
375 to, floatformat_from_type (to_type));
376 return;
377 }
378
379 if (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT
380 && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT)
381 {
382 decimal_convert (from, TYPE_LENGTH (from_type),
383 gdbarch_byte_order (get_type_arch (from_type)),
384 to, TYPE_LENGTH (to_type),
385 gdbarch_byte_order (get_type_arch (to_type)));
386 return;
387 }
388
389 /* We cannot directly convert between binary and decimal floating-point
390 types, so go via an intermediary string. */
391
392 if ((TYPE_CODE (from_type) == TYPE_CODE_FLT
393 && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT)
394 || (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT
395 && TYPE_CODE (to_type) == TYPE_CODE_FLT))
396 {
397 std::string str = target_float_to_string (from, from_type);
398 target_float_from_string (to, to_type, str);
399 return;
400 }
401
402 gdb_assert_not_reached ("unexpected type code");
403}
66c02b9e
UW
404
405/* Perform the binary operation indicated by OPCODE, using as operands the
406 target byte streams X and Y, interpreted as floating-point numbers of
407 types TYPE_X and TYPE_Y, respectively. Convert the result to type
408 TYPE_RES and store it into the byte-stream RES.
409
410 The three types must either be all binary floating-point types, or else
411 all decimal floating-point types. Binary and decimal floating-point
412 types cannot be mixed within a single operation. */
413void
414target_float_binop (enum exp_opcode opcode,
415 const gdb_byte *x, const struct type *type_x,
416 const gdb_byte *y, const struct type *type_y,
417 gdb_byte *res, const struct type *type_res)
418{
419 /* Ensure possible padding bytes in the target buffer are zeroed out. */
420 memset (res, 0, TYPE_LENGTH (type_res));
421
422 if (TYPE_CODE (type_res) == TYPE_CODE_FLT)
423 {
424 gdb_assert (TYPE_CODE (type_x) == TYPE_CODE_FLT);
425 gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_FLT);
426 return floatformat_binop (opcode,
427 floatformat_from_type (type_x), x,
428 floatformat_from_type (type_y), y,
429 floatformat_from_type (type_res), res);
430 }
431
432 if (TYPE_CODE (type_res) == TYPE_CODE_DECFLOAT)
433 {
434 gdb_assert (TYPE_CODE (type_x) == TYPE_CODE_DECFLOAT);
435 gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_DECFLOAT);
436 return decimal_binop (opcode,
437 x, TYPE_LENGTH (type_x),
438 gdbarch_byte_order (get_type_arch (type_x)),
439 y, TYPE_LENGTH (type_y),
440 gdbarch_byte_order (get_type_arch (type_y)),
441 res, TYPE_LENGTH (type_res),
442 gdbarch_byte_order (get_type_arch (type_res)));
443 }
444
445 gdb_assert_not_reached ("unexpected type code");
446}
447
448/* Compare the two target byte streams X and Y, interpreted as floating-point
449 numbers of types TYPE_X and TYPE_Y, respectively. Return zero if X and Y
450 are equal, -1 if X is less than Y, and 1 otherwise.
451
452 The two types must either both be binary floating-point types, or else
453 both be decimal floating-point types. Binary and decimal floating-point
454 types cannot compared directly against each other. */
455int
456target_float_compare (const gdb_byte *x, const struct type *type_x,
457 const gdb_byte *y, const struct type *type_y)
458{
459 if (TYPE_CODE (type_x) == TYPE_CODE_FLT)
460 {
461 gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_FLT);
462 return floatformat_compare (floatformat_from_type (type_x), x,
463 floatformat_from_type (type_y), y);
464 }
465
466 if (TYPE_CODE (type_x) == TYPE_CODE_DECFLOAT)
467 {
468 gdb_assert (TYPE_CODE (type_y) == TYPE_CODE_DECFLOAT);
469 return decimal_compare (x, TYPE_LENGTH (type_x),
470 gdbarch_byte_order (get_type_arch (type_x)),
471 y, TYPE_LENGTH (type_y),
472 gdbarch_byte_order (get_type_arch (type_y)));
473 }
474
475 gdb_assert_not_reached ("unexpected type code");
476}
477
This page took 0.055421 seconds and 4 git commands to generate.