]> Git Repo - binutils.git/blob - sim/common/sim-fpu.h
Automatic date update in version.in
[binutils.git] / sim / common / sim-fpu.h
1 /* Simulator Floating-point support.
2
3    Copyright 1997-2022 Free Software Foundation, Inc.
4
5    Contributed by Cygnus Support.
6
7 This file is part of GDB, the GNU debugger.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program 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
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22
23
24 #ifndef SIM_FPU_H
25 #define SIM_FPU_H
26
27
28 #include <stdbool.h>
29
30
31 /* The FPU intermediate type - this object, passed by reference,
32    should be treated as opaque.
33
34
35    Pragmatics - pass struct by ref:
36
37    The alternatives for this object/interface that were considered
38    were: a packed 64 bit value; an unpacked structure passed by value;
39    and an unpacked structure passed by reference.
40
41    The packed 64 bit value was rejected because: it limited the
42    precision of intermediate values; reasonable performance would only
43    be achieved when the sim_fpu package was in-lined allowing repeated
44    unpacking operations to be eliminated.
45
46    For unpacked structures (passed by value and reference), the code
47    quality of GCC-2.7 (on x86) for each alternative was compared.
48    Needless to say the results, while better than for a packed 64 bit
49    object, were still poor (GCC had only limited support for the
50    optimization of references to structure members).  Regardless, the
51    struct-by-ref alternative achieved better results when compiled
52    with (better speed) and without (better code density) in-lining.
53    Here's looking forward to an improved GCC optimizer.
54
55
56    Pragmatics - avoid host FP hardware:
57
58    FP operations can be implemented by either: the host's floating
59    point hardware; or by emulating the FP operations using integer
60    only routines.  This is direct tradeoff between speed, portability
61    and correctness.
62
63    The two principal reasons for selecting portability and correctness
64    over speed are:
65
66    1 - Correctness.  The assumption that FP correctness wasn't an
67    issue for code being run on simulators was wrong.  Instead of
68    running FP tolerant (?) code, simulator users instead typically run
69    very aggressive FP code sequences.  The sole purpose of those
70    sequences being to test the target ISA's FP implementation.
71
72    2 - Portability.  The host FP implementation is not predictable.  A
73    simulator modeling aggressive FP code sequences using the hosts FPU
74    relies heavily on the correctness of the hosts FP implementation.
75    It turns out that such trust can be misplaced.  The behavior of
76    host FP implementations when handling edge conditions such as SNaNs
77    and exceptions varied widely.
78
79
80    */
81
82
83 typedef enum
84 {
85   sim_fpu_class_zero,
86   sim_fpu_class_snan,
87   sim_fpu_class_qnan,
88   sim_fpu_class_number,
89   sim_fpu_class_denorm,
90   sim_fpu_class_infinity,
91 } sim_fpu_class;
92
93 typedef struct _sim_fpu {
94   sim_fpu_class class;
95   int sign;
96   uint64_t fraction;
97   int normal_exp;
98 } sim_fpu;
99
100
101
102 /* Rounding options.
103
104    The value zero (sim_fpu_round_default) for ALU operations indicates
105    that, when possible, rounding should be avoided. */
106
107 typedef enum
108 {
109   sim_fpu_round_default = 0,
110   sim_fpu_round_near = 1,
111   sim_fpu_round_zero = 2,
112   sim_fpu_round_up = 3,
113   sim_fpu_round_down = 4,
114 } sim_fpu_round;
115
116
117 /* Options when handling denormalized numbers.  */
118
119 typedef enum
120 {
121   sim_fpu_denorm_default = 0,
122   sim_fpu_denorm_underflow_inexact = 1,
123   sim_fpu_denorm_zero = 2,
124 } sim_fpu_denorm;
125
126
127
128 /* Status values returned by FPU operators.
129
130    When checking the result of an FP sequence (ex 32to, add, single,
131    to32) the caller may either: check the return value of each FP
132    operator; or form the union (OR) of the returned values and examine
133    them once at the end.
134
135    FIXME: This facility is still being developed.  The choice of
136    status values returned and their exact meaning may changed in the
137    future.  */
138
139 typedef enum
140 {
141   sim_fpu_status_invalid_snan = 1,
142   sim_fpu_status_invalid_qnan = 2,
143   sim_fpu_status_invalid_isi = 4, /* (inf - inf) */
144   sim_fpu_status_invalid_idi = 8, /* (inf / inf) */
145   sim_fpu_status_invalid_zdz = 16, /* (0 / 0) */
146   sim_fpu_status_invalid_imz = 32, /* (inf * 0) */
147   sim_fpu_status_invalid_cvi = 64, /* convert to integer */
148   sim_fpu_status_invalid_div0 = 128, /* (X / 0) */
149   sim_fpu_status_invalid_cmp = 256, /* compare */
150   sim_fpu_status_invalid_sqrt = 512,
151   sim_fpu_status_invalid_irx = 1024, /* (inf % X) */
152   sim_fpu_status_rounded = 2048,
153   sim_fpu_status_inexact = 4096,
154   sim_fpu_status_overflow = 8192,
155   sim_fpu_status_underflow = 16384,
156   sim_fpu_status_denorm = 32768,
157 } sim_fpu_status;
158
159
160
161
162 /* State used by the FPU.
163
164    FIXME: This state is global, but should be moved to SIM_CPU.  */
165
166 typedef enum
167 {
168   sim_fpu_ieee754_1985,
169   sim_fpu_ieee754_2008,
170 } sim_fpu_mode;
171
172 typedef struct _sim_fpu_state {
173   bool quiet_nan_inverted; /* Toggle quiet NaN semantics.  */
174   sim_fpu_mode current_mode;
175 } sim_fpu_state;
176
177
178
179
180 /* Directly map between a 32/64 bit register and the sim_fpu internal
181    type.
182
183    When converting from the 32/64 bit packed format to the sim_fpu
184    internal type, the operation is exact.
185
186    When converting from the sim_fpu internal type to 32/64 bit packed
187    format, the operation may result in a loss of precision. The
188    configuration macro WITH_FPU_CONVERSION controls this.  By default,
189    silent round to nearest is performed.  Alternatively, round up,
190    round down and round to zero can be performed.  In a simulator
191    emulating exact FPU behavior, sim_fpu_round_{32,64} should be
192    called before packing the sim_fpu value.  */
193
194 INLINE_SIM_FPU (void) sim_fpu_32to (sim_fpu *f, uint32_t s);
195 INLINE_SIM_FPU (void) sim_fpu_232to (sim_fpu *f, uint32_t h, uint32_t l);
196 INLINE_SIM_FPU (void) sim_fpu_64to (sim_fpu *f, uint64_t d);
197
198 INLINE_SIM_FPU (void) sim_fpu_to32 (uint32_t *s, const sim_fpu *f);
199 INLINE_SIM_FPU (void) sim_fpu_to232 (uint32_t *h, uint32_t *l, const sim_fpu *f);
200 INLINE_SIM_FPU (void) sim_fpu_to64 (uint64_t *d, const sim_fpu *f);
201
202
203 /* Create a sim_fpu struct using raw information.  (FRACTION & LSMASK
204    (PRECISION-1, 0)) is assumed to contain the fraction part of the
205    floating-point number.  The leading bit LSBIT (PRECISION) is always
206    implied.  The number created can be represented by:
207
208    (SIGN ? "-" : "+") "1." FRACTION{PRECISION-1,0} X 2 ^ NORMAL_EXP>
209
210    You can not specify zero using this function. */
211
212 INLINE_SIM_FPU (void) sim_fpu_fractionto (sim_fpu *f, int sign, int normal_exp, uint64_t fraction, int precision);
213
214 /* Reverse operation.  If S is a non-zero number, discards the implied
215    leading one and returns PRECISION fraction bits.  No rounding is
216    performed. */
217 INLINE_SIM_FPU (uint64_t) sim_fpu_tofraction (const sim_fpu *s, int precision);
218
219
220
221 /* Rounding operators.
222
223    Force an intermediate result to an exact 32/64 bit
224    representation. */
225
226 INLINE_SIM_FPU (int) sim_fpu_round_32 (sim_fpu *f,
227                                        sim_fpu_round round,
228                                        sim_fpu_denorm denorm);
229 INLINE_SIM_FPU (int) sim_fpu_round_64 (sim_fpu *f,
230                                        sim_fpu_round round,
231                                        sim_fpu_denorm denorm);
232
233
234
235 /* Arithmetic operators.
236
237    FIXME: In the future, additional arguments ROUNDING and BITSIZE may
238    be added. */
239
240 typedef int (sim_fpu_op1) (sim_fpu *f,
241                            const sim_fpu *l);
242 typedef int (sim_fpu_op2) (sim_fpu *f,
243                            const sim_fpu *l,
244                            const sim_fpu *r);
245
246 INLINE_SIM_FPU (int) sim_fpu_add (sim_fpu *f,
247                                   const sim_fpu *l, const sim_fpu *r);
248 INLINE_SIM_FPU (int) sim_fpu_sub (sim_fpu *f,
249                                   const sim_fpu *l, const sim_fpu *r);
250 INLINE_SIM_FPU (int) sim_fpu_mul (sim_fpu *f,
251                                   const sim_fpu *l, const sim_fpu *r);
252 INLINE_SIM_FPU (int) sim_fpu_div (sim_fpu *f,
253                                   const sim_fpu *l, const sim_fpu *r);
254 INLINE_SIM_FPU (int) sim_fpu_rem (sim_fpu *f,
255                                   const sim_fpu *l, const sim_fpu *r);
256 INLINE_SIM_FPU (int) sim_fpu_max (sim_fpu *f,
257                                   const sim_fpu *l, const sim_fpu *r);
258 INLINE_SIM_FPU (int) sim_fpu_min (sim_fpu *f,
259                                   const sim_fpu *l, const sim_fpu *r);
260 INLINE_SIM_FPU (int) sim_fpu_neg (sim_fpu *f,
261                                   const sim_fpu *a);
262 INLINE_SIM_FPU (int) sim_fpu_abs (sim_fpu *f,
263                                   const sim_fpu *a);
264 INLINE_SIM_FPU (int) sim_fpu_inv (sim_fpu *f,
265                                   const sim_fpu *a);
266 INLINE_SIM_FPU (int) sim_fpu_sqrt (sim_fpu *f,
267                                    const sim_fpu *sqr);
268
269
270
271 /* NaN handling.
272
273    Assuming that at least one of the inputs is NAN choose the correct
274    NAN result for the binary operation.  */
275
276 INLINE_SIM_FPU (int) sim_fpu_op_nan (sim_fpu *f,
277                                      const sim_fpu *l, const sim_fpu *r);
278 INLINE_SIM_FPU (int) sim_fpu_minmax_nan (sim_fpu *f,
279                                          const sim_fpu *l, const sim_fpu *r);
280
281
282
283 /* Conversion of integer <-> floating point. */
284
285 INLINE_SIM_FPU (int) sim_fpu_i32to (sim_fpu *f, int32_t i,
286                                     sim_fpu_round round);
287 INLINE_SIM_FPU (int) sim_fpu_u32to (sim_fpu *f, uint32_t u,
288                                     sim_fpu_round round);
289 INLINE_SIM_FPU (int) sim_fpu_i64to (sim_fpu *f, int64_t i,
290                                     sim_fpu_round round);
291 INLINE_SIM_FPU (int) sim_fpu_u64to (sim_fpu *f, uint64_t u,
292                                     sim_fpu_round round);
293 #if 0
294 INLINE_SIM_FPU (int) sim_fpu_i232to (sim_fpu *f, int32_t h, int32_t l,
295                                      sim_fpu_round round);
296 #endif
297 #if 0
298 INLINE_SIM_FPU (int) sim_fpu_u232to (sim_fpu *f, uint32_t h, uint32_t l,
299                                      sim_fpu_round round);
300 #endif
301
302 INLINE_SIM_FPU (int) sim_fpu_to32i (int32_t *i, const sim_fpu *f,
303                                     sim_fpu_round round);
304 INLINE_SIM_FPU (int) sim_fpu_to32u (uint32_t *u, const sim_fpu *f,
305                                     sim_fpu_round round);
306 INLINE_SIM_FPU (int) sim_fpu_to64i (int64_t *i, const sim_fpu *f,
307                                     sim_fpu_round round);
308 INLINE_SIM_FPU (int) sim_fpu_to64u (uint64_t *u, const sim_fpu *f,
309                                     sim_fpu_round round);
310 #if 0
311 INLINE_SIM_FPU (int) sim_fpu_to232i (int64_t *h, int64_t *l, const sim_fpu *f,
312                                      sim_fpu_round round);
313 #endif
314 #if 0
315 INLINE_SIM_FPU (int) sim_fpu_to232u (uint64_t *h, uint64_t *l, const sim_fpu *f,
316                                      sim_fpu_round round);
317 #endif
318
319
320 /* Conversion of internal sim_fpu type to host double format.
321
322    For debugging/tracing only.  A SNaN is never returned. */
323
324 /* INLINE_SIM_FPU (float) sim_fpu_2f (const sim_fpu *f); */
325 INLINE_SIM_FPU (double) sim_fpu_2d (const sim_fpu *d);
326
327 /* INLINE_SIM_FPU (void) sim_fpu_f2 (sim_fpu *f, float s); */
328 INLINE_SIM_FPU (void) sim_fpu_d2 (sim_fpu *f, double d);
329
330 /* IEEE754-2008 classifiction function.  */
331 INLINE_SIM_FPU (int) sim_fpu_classify (const sim_fpu *f);
332
333 /* Specific number classes.
334
335    NB: When either, a 32/64 bit floating points is converted to
336    internal format, or an internal format number is rounded to 32/64
337    bit precision, a special marker is retained that indicates that the
338    value was normalized.  For such numbers both is_number and
339    is_denorm return true. */
340
341 INLINE_SIM_FPU (int) sim_fpu_is_nan (const sim_fpu *s); /* 1 => SNaN or QNaN */
342 INLINE_SIM_FPU (int) sim_fpu_is_snan (const sim_fpu *s); /* 1 => SNaN */
343 INLINE_SIM_FPU (int) sim_fpu_is_qnan (const sim_fpu *s); /* 1 => QNaN */
344
345 INLINE_SIM_FPU (int) sim_fpu_is_zero (const sim_fpu *s);
346 INLINE_SIM_FPU (int) sim_fpu_is_infinity (const sim_fpu *s);
347 INLINE_SIM_FPU (int) sim_fpu_is_number (const sim_fpu *s); /* !zero */
348 INLINE_SIM_FPU (int) sim_fpu_is_denorm (const sim_fpu *s); /* !zero */
349
350
351
352 /* Floating point fields */
353
354 INLINE_SIM_FPU (int) sim_fpu_sign (const sim_fpu *s);
355 INLINE_SIM_FPU (int) sim_fpu_exp (const sim_fpu *s);
356 INLINE_SIM_FPU (uint64_t) sim_fpu_fraction (const sim_fpu *s);
357 INLINE_SIM_FPU (uint64_t) sim_fpu_guard (const sim_fpu *s, int is_double);
358
359
360
361 /* Specific comparison operators
362
363    For NaNs et al., the comparison operators will set IS to zero and
364    return a nonzero result. */
365
366 INLINE_SIM_FPU (int) sim_fpu_lt (int *is, const sim_fpu *l, const sim_fpu *r);
367 INLINE_SIM_FPU (int) sim_fpu_le (int *is, const sim_fpu *l, const sim_fpu *r);
368 INLINE_SIM_FPU (int) sim_fpu_eq (int *is, const sim_fpu *l, const sim_fpu *r);
369 INLINE_SIM_FPU (int) sim_fpu_ne (int *is, const sim_fpu *l, const sim_fpu *r);
370 INLINE_SIM_FPU (int) sim_fpu_ge (int *is, const sim_fpu *l, const sim_fpu *r);
371 INLINE_SIM_FPU (int) sim_fpu_gt (int *is, const sim_fpu *l, const sim_fpu *r);
372
373 INLINE_SIM_FPU (int) sim_fpu_is_lt (const sim_fpu *l, const sim_fpu *r);
374 INLINE_SIM_FPU (int) sim_fpu_is_le (const sim_fpu *l, const sim_fpu *r);
375 INLINE_SIM_FPU (int) sim_fpu_is_eq (const sim_fpu *l, const sim_fpu *r);
376 INLINE_SIM_FPU (int) sim_fpu_is_ne (const sim_fpu *l, const sim_fpu *r);
377 INLINE_SIM_FPU (int) sim_fpu_is_ge (const sim_fpu *l, const sim_fpu *r);
378 INLINE_SIM_FPU (int) sim_fpu_is_gt (const sim_fpu *l, const sim_fpu *r);
379
380 /* Unordered/ordered comparison operators.  */
381
382 INLINE_SIM_FPU (int) sim_fpu_un (int *is, const sim_fpu *l, const sim_fpu *r);
383 INLINE_SIM_FPU (int) sim_fpu_or (int *is, const sim_fpu *l, const sim_fpu *r);
384
385 INLINE_SIM_FPU (int) sim_fpu_is_un (const sim_fpu *l, const sim_fpu *r);
386 INLINE_SIM_FPU (int) sim_fpu_is_or (const sim_fpu *l, const sim_fpu *r);
387
388 /* Changes the behaviour of the library to IEEE754-2008 or IEEE754-1985.
389    The default for the library is IEEE754-1985.  */
390
391 INLINE_SIM_FPU (bool) sim_fpu_is_ieee754_1985 (void);
392 INLINE_SIM_FPU (bool) sim_fpu_is_ieee754_2008 (void);
393 INLINE_SIM_FPU (void) sim_fpu_set_mode (const sim_fpu_mode m);
394
395 /* General number class and comparison operators.
396
397    The result of the comparison is indicated by returning one of the
398    values below.  Efficient emulation of a target FP compare
399    instruction can be achieved by redefining the values below to match
400    corresponding target FP status bits.
401
402    For instance.  SIM_FPU_QNAN may be redefined to be the bit
403    `INVALID' while SIM_FPU_NINF might be redefined as the bits
404    `NEGATIVE | INFINITY | VALID'. */
405
406 #ifndef SIM_FPU_IS_SNAN
407 enum {
408   SIM_FPU_IS_SNAN = 1, /* Noisy not-a-number */
409   SIM_FPU_IS_QNAN = 2, /* Quiet not-a-number */
410   SIM_FPU_IS_NINF = 3, /* -infinity */
411   SIM_FPU_IS_PINF = 4, /* +infinity */
412   SIM_FPU_IS_NNUMBER = 5, /* -number - [ -MAX .. -MIN ] */
413   SIM_FPU_IS_PNUMBER = 6, /* +number - [ +MIN .. +MAX ] */
414   SIM_FPU_IS_NDENORM = 7, /* -denorm - ( MIN .. 0 ) */
415   SIM_FPU_IS_PDENORM = 8, /* +denorm - ( 0 .. MIN ) */
416   SIM_FPU_IS_NZERO = 9, /* -0 */
417   SIM_FPU_IS_PZERO = 10, /* +0 */
418 };
419 #endif
420
421 INLINE_SIM_FPU (int) sim_fpu_is (const sim_fpu *l);
422 INLINE_SIM_FPU (int) sim_fpu_cmp (const sim_fpu *l, const sim_fpu *r);
423
424 /* Global FPU state.  */
425
426 extern sim_fpu_state _sim_fpu;
427
428
429 /* IEEE 754-1985 specifies the top bit of the mantissa as an indicator
430    of signalling vs. quiet NaN, but does not specify the semantics.
431    Most architectures treat this bit as quiet NaN, but legacy (pre-R6)
432    MIPS goes the other way and treats it as signalling.  This variable
433    tracks the current semantics of the NaN bit and allows differentiation
434    between pre-R6 and R6 MIPS cores.  */
435
436 #define sim_fpu_quiet_nan_inverted _sim_fpu.quiet_nan_inverted
437 #define sim_fpu_current_mode _sim_fpu.current_mode
438
439 /* A number of useful constants.  */
440
441 extern const sim_fpu sim_fpu_zero;
442 extern const sim_fpu sim_fpu_one;
443 extern const sim_fpu sim_fpu_two;
444 extern const sim_fpu sim_fpu_qnan;
445 extern const sim_fpu sim_fpu_max32;
446 extern const sim_fpu sim_fpu_max64;
447
448
449 /* Select the applicable functions for the fp_word type */
450
451 #if WITH_TARGET_FLOATING_POINT_BITSIZE == 32
452 #define sim_fpu_tofp sim_fpu_to32
453 #define sim_fpu_fpto sim_fpu_32to
454 #define sim_fpu_round_fp sim_fpu_round_32
455 #define sim_fpu_maxfp sim_fpu_max32
456 #endif
457 #if WITH_TARGET_FLOATING_POINT_BITSIZE == 64
458 #define sim_fpu_tofp sim_fpu_to64
459 #define sim_fpu_fpto sim_fpu_64to
460 #define sim_fpu_round_fp sim_fpu_round_64
461 #define sim_fpu_maxfp sim_fpu_max64
462 #endif
463
464
465
466 /* For debugging */
467
468 typedef void sim_fpu_print_func (void *, const char *, ...);
469
470 /* Print a sim_fpu with full precision.  */
471 INLINE_SIM_FPU (void) sim_fpu_print_fpu (const sim_fpu *f,
472                                          sim_fpu_print_func *print,
473                                          void *arg);
474
475 /* Print a sim_fpu with `n' trailing digits.  */
476 INLINE_SIM_FPU (void) sim_fpu_printn_fpu (const sim_fpu *f,
477                                           sim_fpu_print_func *print,
478                                           int digits,
479                                           void *arg);
480
481 INLINE_SIM_FPU (void) sim_fpu_print_status (int status,
482                                             sim_fpu_print_func *print,
483                                             void *arg);
484
485 #if H_REVEALS_MODULE_P (SIM_FPU_INLINE)
486 #include "sim-fpu.c"
487 #endif
488
489 #endif
This page took 0.049947 seconds and 4 git commands to generate.