1/* Copyright (C) 2007-2022 Free Software Foundation, Inc.
2
3This file is part of GCC.
4
5GCC is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free
7Software Foundation; either version 3, or (at your option) any later
8version.
9
10GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13for more details.
14
15Under Section 7 of GPL version 3, you are granted additional
16permissions described in the GCC Runtime Library Exception, version
173.1, as published by the Free Software Foundation.
18
19You should have received a copy of the GNU General Public License and
20a copy of the GCC Runtime Library Exception along with this program;
21see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22<http://www.gnu.org/licenses/>.  */
23
24/*****************************************************************************
25 *    Non-computational Operations on Flags:
26 ****************************************************************************/
27
28#include "bid_internal.h"
29
30// Note the following definitions from bid_conf.h: if the status flags are
31// global, they have a fixed name recognized by the library functions:
32// _IDEC_glbflags; pfpsf, defined as &_IDEC_glbflags, can be used instead; no
33// argument is passed for the status flags to the library functions; if the
34// status flags are local then they are passed as an arument, always by
35// reference, to the library functions
36//
37// #if !DECIMAL_GLOBAL_EXCEPTION_FLAGS
38//   #define _EXC_FLAGS_PARAM , _IDEC_flags *pfpsf
39// #else
40//   extern _IDEC_flags _IDEC_glbflags;
41//   #define _EXC_FLAGS_PARAM
42//   #define pfpsf &_IDEC_glbflags
43// #endif
44
45#if DECIMAL_CALL_BY_REFERENCE
46void
47signalException (_IDEC_flags * pflagsmask _EXC_FLAGS_PARAM) {
48  // *pflagsmask is the logical OR of the flags to be set, e.g.
49  // *pflagsmask =INVALID_EXCEPTION | ZERO_DIVIDE_EXCEPTION | OVERFLOW_EXCEPTION
50  // UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION to set all five IEEE 754R
51  // exception flags
52  *pfpsf = *pfpsf | (*pflagsmask & BID_IEEE_FLAGS);
53}
54#else
55void
56signalException (_IDEC_flags flagsmask _EXC_FLAGS_PARAM) {
57  // flagsmask is the logical OR of the flags to be set, e.g.
58  // flagsmask = INVALID_EXCEPTION | ZERO_DIVIDE_EXCEPTION | OVERFLOW_EXCEPTION
59  // UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION to set all five IEEE 754R
60  // exception flags
61  *pfpsf = *pfpsf | (flagsmask & BID_IEEE_FLAGS);
62}
63#endif
64
65#if DECIMAL_CALL_BY_REFERENCE
66void
67lowerFlags (_IDEC_flags * pflagsmask _EXC_FLAGS_PARAM) {
68  // *pflagsmask is the logical OR of the flags to be cleared, e.g.
69  // *pflagsmask =INVALID_EXCEPTION | ZERO_DIVIDE_EXCEPTION | OVERFLOW_EXCEPTION
70  // UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION to clear all five IEEE 754R
71  // exception flags
72  *pfpsf = *pfpsf & ~(*pflagsmask & BID_IEEE_FLAGS);
73}
74#else
75void
76lowerFlags (_IDEC_flags flagsmask _EXC_FLAGS_PARAM) {
77  // flagsmask is the logical OR of the flags to be cleared, e.g.
78  // flagsmask = INVALID_EXCEPTION | ZERO_DIVIDE_EXCEPTION | OVERFLOW_EXCEPTION
79  // UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION to clear all five IEEE 754R
80  // exception flags
81  *pfpsf = *pfpsf & ~(flagsmask & BID_IEEE_FLAGS);
82}
83#endif
84
85#if DECIMAL_CALL_BY_REFERENCE
86void
87testFlags (_IDEC_flags * praised,
88	   _IDEC_flags * pflagsmask _EXC_FLAGS_PARAM) {
89  // *praised is a pointer to the result, i.e. the logical OR of the flags
90  // selected by *pflagsmask that are set; e.g. if
91  // *pflagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION
92  // and only the invalid and inexact flags are raised (set) then upon return
93  // *praised = INVALID_EXCEPTION | INEXACT_EXCEPTION
94  *praised = *pfpsf & (*pflagsmask & BID_IEEE_FLAGS);
95}
96#else
97_IDEC_flags
98testFlags (_IDEC_flags flagsmask _EXC_FLAGS_PARAM) {
99  _IDEC_flags raised;
100  // the raturn value raised is the logical OR of the flags
101  // selected by flagsmask, that are set; e.g. if
102  // flagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION and
103  // only the invalid and inexact flags are raised (set) then the return value
104  // is raised = INVALID_EXCEPTION | INEXACT_EXCEPTION
105  raised = *pfpsf & (flagsmask & BID_IEEE_FLAGS);
106  return (raised);
107}
108#endif
109
110#if DECIMAL_CALL_BY_REFERENCE
111void
112testSavedFlags (_IDEC_flags * praised, _IDEC_flags * psavedflags,
113		_IDEC_flags * pflagsmask) {
114  // *praised is a pointer to the result, i.e. the logical OR of the flags
115  // selected by *pflagsmask that are set in *psavedflags; e.g. if
116  // *pflagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION
117  // and only the invalid and inexact flags are raised (set) in *psavedflags
118  // then upon return *praised = INVALID_EXCEPTION | INEXACT_EXCEPTION
119  // Note that the flags could be saved in a global variable, but this function
120  // would still expect that value as an argument passed by reference
121  *praised = *psavedflags & (*pflagsmask & BID_IEEE_FLAGS);
122}
123#else
124_IDEC_flags
125testSavedFlags (_IDEC_flags savedflags, _IDEC_flags flagsmask) {
126  _IDEC_flags raised;
127  // the raturn value raised is the logical OR of the flags
128  // selected by flagsmask, that are set in savedflags; e.g. if
129  // flagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION and
130  // only the invalid and inexact flags are raised (set) in savedflags
131  // then the return value is raised = INVALID_EXCEPTION | INEXACT_EXCEPTION
132  // Note that the flags could be saved in a global variable, but this function
133  // would still expect that value as an argument passed by value
134  raised = savedflags & (flagsmask & BID_IEEE_FLAGS);
135  return (raised);
136}
137#endif
138
139#if DECIMAL_CALL_BY_REFERENCE
140void
141restoreFlags (_IDEC_flags * pflagsvalues,
142	      _IDEC_flags * pflagsmask _EXC_FLAGS_PARAM) {
143  // restore the status flags selected by *pflagsmask to the values speciafied
144  // (as a logical OR) in *pflagsvalues; e.g. if
145  // *pflagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION
146  // and only the invalid and inexact flags are raised (set) in *pflagsvalues
147  // then upon return the invalid status flag will be set, the underflow status
148  // flag will be clear, and the inexact status flag will be set
149  *pfpsf = *pfpsf & ~(*pflagsmask & BID_IEEE_FLAGS);
150  // clear flags that have to be restored
151  *pfpsf = *pfpsf | (*pflagsvalues & (*pflagsmask & BID_IEEE_FLAGS));
152  // restore flags
153}
154#else
155void
156restoreFlags (_IDEC_flags flagsvalues,
157	      _IDEC_flags flagsmask _EXC_FLAGS_PARAM) {
158  // restore the status flags selected by flagsmask to the values speciafied
159  // (as a logical OR) in flagsvalues; e.g. if
160  // flagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION
161  // and only the invalid and inexact flags are raised (set) in flagsvalues
162  // then upon return the invalid status flag will be set, the underflow status
163  // flag will be clear, and the inexact status flag will be set
164  *pfpsf = *pfpsf & ~(flagsmask & BID_IEEE_FLAGS);
165  // clear flags that have to be restored
166  *pfpsf = *pfpsf | (flagsvalues & (flagsmask & BID_IEEE_FLAGS));
167  // restore flags
168}
169#endif
170
171#if DECIMAL_CALL_BY_REFERENCE
172void
173saveFlags (_IDEC_flags * pflagsvalues,
174	   _IDEC_flags * pflagsmask _EXC_FLAGS_PARAM) {
175  // return in *pflagsvalues the status flags specified (as a logical OR) in
176  // *pflagsmask; e.g. if
177  // *pflagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION
178  // and only the invalid and inexact flags are raised (set) in the status word,
179  // then upon return the value in *pflagsvalues will have the invalid status
180  // flag set, the underflow status flag clear, and the inexact status flag set
181  *pflagsvalues = *pfpsf & (*pflagsmask & BID_IEEE_FLAGS);
182}
183#else
184_IDEC_flags
185saveFlags (_IDEC_flags flagsmask _EXC_FLAGS_PARAM) {
186  _IDEC_flags flagsvalues;
187  // return the status flags specified (as a logical OR) in flagsmask; e.g. if
188  // flagsmask = INVALID_EXCEPTION | UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION
189  // and only the invalid and inexact flags are raised (set) in the status word,
190  // then the return value will have the invalid status  flag set, the
191  // underflow status flag clear, and the inexact status flag set
192  flagsvalues = *pfpsf & (flagsmask & BID_IEEE_FLAGS);
193  return (flagsvalues);
194}
195#endif
196
197// Note the following definitions from bid_conf.h (rearranged): if the rounding
198// mode is global, it has a fixed name recognized by the library functions:
199// _IDEC_glbround; rnd_mode, defined as &_IDEC_glbround, can be used instead; no
200// argument is passed for the rounding mode to the library functions; if the
201// rounding mode is local then it is passed as an arument, by reference or by
202// value, to the library functions
203//
204// #if DECIMAL_CALL_BY_REFERENCE
205//   #if !DECIMAL_GLOBAL_ROUNDING
206//     #define _RND_MODE_PARAM , _IDEC_round *prnd_mode
207//   #else
208//     #define _RND_MODE_PARAM
209//     #define rnd_mode _IDEC_glbround
210//   #endif
211// #else
212//   #if !DECIMAL_GLOBAL_ROUNDING
213//     #define _RND_MODE_PARAM , _IDEC_round rnd_mode
214//   #else
215//     #define _RND_MODE_PARAM
216//     #define rnd_mode _IDEC_glbround
217//   #endif
218// #endif
219
220#if DECIMAL_CALL_BY_REFERENCE
221#if !DECIMAL_GLOBAL_ROUNDING
222    // #define _RND_MODE_PARAM , _IDEC_round *prnd_mode
223void
224getDecimalRoundingDirection (_IDEC_round * rounding_mode
225			     _RND_MODE_PARAM) {
226  // returns the current rounding mode
227  *rounding_mode = *prnd_mode;
228}
229#else
230    // #define _RND_MODE_PARAM
231    // #define rnd_mode _IDEC_glbround
232void
233getDecimalRoundingDirection (_IDEC_round * rounding_mode
234			     _RND_MODE_PARAM) {
235  // returns the current rounding mode
236  *rounding_mode = rnd_mode;
237}
238#endif
239#else
240#if !DECIMAL_GLOBAL_ROUNDING
241    // #define _RND_MODE_PARAM , _IDEC_round rnd_mode
242_IDEC_round
243getDecimalRoundingDirection (_IDEC_round rnd_mode) {
244  // returns the current rounding mode
245  return (rnd_mode);
246}
247#else
248    // #define _RND_MODE_PARAM
249    // #define rnd_mode _IDEC_glbround
250_IDEC_round
251getDecimalRoundingDirection (void) {
252  // returns the current rounding mode
253  return (rnd_mode);
254}
255#endif
256#endif
257
258#if DECIMAL_CALL_BY_REFERENCE
259#if !DECIMAL_GLOBAL_ROUNDING
260    // #define _RND_MODE_PARAM , _IDEC_round *prnd_mode
261void
262setDecimalRoundingDirection (_IDEC_round * rounding_mode
263			     _RND_MODE_PARAM) {
264  // sets the current rounding mode to the value in *rounding_mode, if valid
265  if (*rounding_mode == ROUNDING_TO_NEAREST ||
266      *rounding_mode == ROUNDING_DOWN ||
267      *rounding_mode == ROUNDING_UP ||
268      *rounding_mode == ROUNDING_TO_ZERO ||
269      *rounding_mode == ROUNDING_TIES_AWAY) {
270    *prnd_mode = *rounding_mode;
271  }
272}
273#else
274    // #define _RND_MODE_PARAM
275    // #define rnd_mode _IDEC_glbround
276void
277setDecimalRoundingDirection (_IDEC_round * rounding_mode
278			     ) {
279  // sets the global rounding mode to the value in *rounding_mode, if valid
280  if (*rounding_mode == ROUNDING_TO_NEAREST ||
281      *rounding_mode == ROUNDING_DOWN ||
282      *rounding_mode == ROUNDING_UP ||
283      *rounding_mode == ROUNDING_TO_ZERO ||
284      *rounding_mode == ROUNDING_TIES_AWAY) {
285    rnd_mode = *rounding_mode;
286  }
287}
288#endif
289#else
290#if !DECIMAL_GLOBAL_ROUNDING
291    // #define _RND_MODE_PARAM , _IDEC_round rnd_mode
292_IDEC_round
293setDecimalRoundingDirection (_IDEC_round rounding_mode _RND_MODE_PARAM) {
294  // sets the current rounding mode to the value in rounding_mode;
295  // however, when arguments are passed by value and the rounding mode
296  // is a local variable, this is not of any use
297  if (rounding_mode == ROUNDING_TO_NEAREST ||
298      rounding_mode == ROUNDING_DOWN ||
299      rounding_mode == ROUNDING_UP ||
300      rounding_mode == ROUNDING_TO_ZERO ||
301      rounding_mode == ROUNDING_TIES_AWAY) {
302    return (rounding_mode);
303  }
304  return (rnd_mode);
305}
306#else
307    // #define _RND_MODE_PARAM
308    // #define rnd_mode _IDEC_glbround
309void
310setDecimalRoundingDirection (_IDEC_round rounding_mode) {
311  // sets the current rounding mode to the value in rounding_mode, if valid;
312  if (rounding_mode == ROUNDING_TO_NEAREST ||
313      rounding_mode == ROUNDING_DOWN ||
314      rounding_mode == ROUNDING_UP ||
315      rounding_mode == ROUNDING_TO_ZERO ||
316      rounding_mode == ROUNDING_TIES_AWAY) {
317    rnd_mode = rounding_mode;
318  }
319}
320#endif
321#endif
322
323#if DECIMAL_CALL_BY_REFERENCE
324void
325is754 (int *retval) {
326  *retval = 0;
327}
328#else
329int
330is754 (void) {
331  return 0;
332}
333#endif
334
335#if DECIMAL_CALL_BY_REFERENCE
336void
337is754R (int *retval) {
338  *retval = 1;
339}
340#else
341int
342is754R (void) {
343  return 1;
344}
345#endif
346