]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/target-float.c
Target FP: Add conversion routines to target-float.{c,h}
[thirdparty/binutils-gdb.git] / gdb / target-float.c
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
28 /* Helper routines operating on binary floating-point data. */
29
30 /* Convert the byte-stream ADDR, interpreted as floating-point format FMT,
31 to an integer value (rounding towards zero). */
32 static LONGEST
33 floatformat_to_longest (const struct floatformat *fmt, const gdb_byte *addr)
34 {
35 DOUBLEST d;
36 floatformat_to_doublest (fmt, addr, &d);
37 return (LONGEST) d;
38 }
39
40 /* Convert signed integer VAL to a target floating-number of format FMT
41 and store it as byte-stream ADDR. */
42 static void
43 floatformat_from_longest (const struct floatformat *fmt, gdb_byte *addr,
44 LONGEST val)
45 {
46 DOUBLEST d = (DOUBLEST) val;
47 floatformat_from_doublest (fmt, &d, addr);
48 }
49
50 /* Convert unsigned integer VAL to a target floating-number of format FMT
51 and store it as byte-stream ADDR. */
52 static void
53 floatformat_from_ulongest (const struct floatformat *fmt, gdb_byte *addr,
54 ULONGEST val)
55 {
56 DOUBLEST d = (DOUBLEST) val;
57 floatformat_from_doublest (fmt, &d, addr);
58 }
59
60 /* Convert a floating-point number of format FROM_FMT from the target
61 byte-stream FROM to a floating-point number of format TO_FMT, and
62 store it to the target byte-stream TO. */
63 static void
64 floatformat_convert (const gdb_byte *from, const struct floatformat *from_fmt,
65 gdb_byte *to, const struct floatformat *to_fmt)
66 {
67 if (from_fmt == to_fmt)
68 {
69 /* The floating-point formats match, so we simply copy the data. */
70 memcpy (to, from, floatformat_totalsize_bytes (to_fmt));
71 }
72 else
73 {
74 /* The floating-point formats don't match. The best we can do
75 (apart from simulating the target FPU) is converting to the
76 widest floating-point type supported by the host, and then
77 again to the desired type. */
78 DOUBLEST d;
79
80 floatformat_to_doublest (from_fmt, from, &d);
81 floatformat_from_doublest (to_fmt, &d, to);
82 }
83 }
84
85
86 /* Typed floating-point routines. These routines operate on floating-point
87 values in target format, represented by a byte buffer interpreted as a
88 "struct type", which may be either a binary or decimal floating-point
89 type (TYPE_CODE_FLT or TYPE_CODE_DECFLOAT). */
90
91 /* Return whether the byte-stream ADDR holds a valid value of
92 floating-point type TYPE. */
93 bool
94 target_float_is_valid (const gdb_byte *addr, const struct type *type)
95 {
96 if (TYPE_CODE (type) == TYPE_CODE_FLT)
97 return floatformat_is_valid (floatformat_from_type (type), addr);
98
99 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
100 return true;
101
102 gdb_assert_not_reached ("unexpected type code");
103 }
104
105 /* Return whether the byte-stream ADDR, interpreted as floating-point
106 type TYPE, is numerically equal to zero (of either sign). */
107 bool
108 target_float_is_zero (const gdb_byte *addr, const struct type *type)
109 {
110 if (TYPE_CODE (type) == TYPE_CODE_FLT)
111 return (floatformat_classify (floatformat_from_type (type), addr)
112 == float_zero);
113
114 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
115 return decimal_is_zero (addr, TYPE_LENGTH (type),
116 gdbarch_byte_order (get_type_arch (type)));
117
118 gdb_assert_not_reached ("unexpected type code");
119 }
120
121 /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
122 to a string, optionally using the print format FORMAT. */
123 std::string
124 target_float_to_string (const gdb_byte *addr, const struct type *type,
125 const char *format)
126 {
127 if (TYPE_CODE (type) == TYPE_CODE_FLT)
128 return floatformat_to_string (floatformat_from_type (type), addr, format);
129
130 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
131 return decimal_to_string (addr, TYPE_LENGTH (type),
132 gdbarch_byte_order (get_type_arch (type)),
133 format);
134
135 gdb_assert_not_reached ("unexpected type code");
136 }
137
138 /* Parse string STRING into a target floating-number of type TYPE and
139 store it as byte-stream ADDR. Return whether parsing succeeded. */
140 bool
141 target_float_from_string (gdb_byte *addr, const struct type *type,
142 const std::string &string)
143 {
144 /* Ensure possible padding bytes in the target buffer are zeroed out. */
145 memset (addr, 0, TYPE_LENGTH (type));
146
147 if (TYPE_CODE (type) == TYPE_CODE_FLT)
148 return floatformat_from_string (floatformat_from_type (type), addr,
149 string);
150
151 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
152 return decimal_from_string (addr, TYPE_LENGTH (type),
153 gdbarch_byte_order (get_type_arch (type)),
154 string);
155
156 gdb_assert_not_reached ("unexpected type code");
157 }
158
159 /* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
160 to an integer value (rounding towards zero). */
161 LONGEST
162 target_float_to_longest (const gdb_byte *addr, const struct type *type)
163 {
164 if (TYPE_CODE (type) == TYPE_CODE_FLT)
165 return floatformat_to_longest (floatformat_from_type (type), addr);
166
167 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
168 return decimal_to_longest (addr, TYPE_LENGTH (type),
169 gdbarch_byte_order (get_type_arch (type)));
170
171 gdb_assert_not_reached ("unexpected type code");
172 }
173
174 /* Convert signed integer VAL to a target floating-number of type TYPE
175 and store it as byte-stream ADDR. */
176 void
177 target_float_from_longest (gdb_byte *addr, const struct type *type,
178 LONGEST val)
179 {
180 /* Ensure possible padding bytes in the target buffer are zeroed out. */
181 memset (addr, 0, TYPE_LENGTH (type));
182
183 if (TYPE_CODE (type) == TYPE_CODE_FLT)
184 {
185 floatformat_from_longest (floatformat_from_type (type), addr, val);
186 return;
187 }
188
189 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
190 {
191 decimal_from_longest (val, addr, TYPE_LENGTH (type),
192 gdbarch_byte_order (get_type_arch (type)));
193 return;
194 }
195
196 gdb_assert_not_reached ("unexpected type code");
197 }
198
199 /* Convert unsigned integer VAL to a target floating-number of type TYPE
200 and store it as byte-stream ADDR. */
201 void
202 target_float_from_ulongest (gdb_byte *addr, const struct type *type,
203 ULONGEST val)
204 {
205 /* Ensure possible padding bytes in the target buffer are zeroed out. */
206 memset (addr, 0, TYPE_LENGTH (type));
207
208 if (TYPE_CODE (type) == TYPE_CODE_FLT)
209 {
210 floatformat_from_ulongest (floatformat_from_type (type), addr, val);
211 return;
212 }
213
214 if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
215 {
216 decimal_from_ulongest (val, addr, TYPE_LENGTH (type),
217 gdbarch_byte_order (get_type_arch (type)));
218 return;
219 }
220
221 gdb_assert_not_reached ("unexpected type code");
222 }
223
224 /* Convert a floating-point number of type FROM_TYPE from the target
225 byte-stream FROM to a floating-point number of type TO_TYPE, and
226 store it to the target byte-stream TO. */
227 void
228 target_float_convert (const gdb_byte *from, const struct type *from_type,
229 gdb_byte *to, const struct type *to_type)
230 {
231 /* Ensure possible padding bytes in the target buffer are zeroed out. */
232 memset (to, 0, TYPE_LENGTH (to_type));
233
234 /* Use direct conversion routines if we have them. */
235
236 if (TYPE_CODE (from_type) == TYPE_CODE_FLT
237 && TYPE_CODE (to_type) == TYPE_CODE_FLT)
238 {
239 floatformat_convert (from, floatformat_from_type (from_type),
240 to, floatformat_from_type (to_type));
241 return;
242 }
243
244 if (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT
245 && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT)
246 {
247 decimal_convert (from, TYPE_LENGTH (from_type),
248 gdbarch_byte_order (get_type_arch (from_type)),
249 to, TYPE_LENGTH (to_type),
250 gdbarch_byte_order (get_type_arch (to_type)));
251 return;
252 }
253
254 /* We cannot directly convert between binary and decimal floating-point
255 types, so go via an intermediary string. */
256
257 if ((TYPE_CODE (from_type) == TYPE_CODE_FLT
258 && TYPE_CODE (to_type) == TYPE_CODE_DECFLOAT)
259 || (TYPE_CODE (from_type) == TYPE_CODE_DECFLOAT
260 && TYPE_CODE (to_type) == TYPE_CODE_FLT))
261 {
262 std::string str = target_float_to_string (from, from_type);
263 target_float_from_string (to, to_type, str);
264 return;
265 }
266
267 gdb_assert_not_reached ("unexpected type code");
268 }