Commit | Line | Data |
---|---|---|
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). */ | |
34 | static LONGEST | |
35 | floatformat_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. */ | |
44 | static void | |
45 | floatformat_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. */ | |
54 | static void | |
55 | floatformat_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. */ | |
64 | static double | |
65 | floatformat_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. */ | |
75 | static void | |
76 | floatformat_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. */ | |
86 | static void | |
87 | floatformat_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. */ | |
112 | static void | |
113 | floatformat_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. */ | |
168 | static int | |
169 | floatformat_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. */ | |
192 | bool | |
193 | target_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). */ | |
206 | bool | |
207 | target_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. */ | |
222 | std::string | |
223 | target_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. */ | |
239 | bool | |
240 | target_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). */ | |
260 | LONGEST | |
261 | target_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. */ | |
275 | void | |
276 | target_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. */ | |
300 | void | |
301 | target_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. */ | |
325 | double | |
326 | target_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. */ | |
340 | void | |
341 | target_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. */ | |
362 | void | |
363 | target_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. */ | |
413 | void | |
414 | target_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. */ | |
455 | int | |
456 | target_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 |