Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Include/internal/pycore_pymath.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef Py_INTERNAL_PYMATH_H
2
#define Py_INTERNAL_PYMATH_H
3
#ifdef __cplusplus
4
extern "C" {
5
#endif
6
7
#ifndef Py_BUILD_CORE
8
#  error "this header requires Py_BUILD_CORE define"
9
#endif
10
11
12
/* _Py_ADJUST_ERANGE1(x)
13
 * _Py_ADJUST_ERANGE2(x, y)
14
 * Set errno to 0 before calling a libm function, and invoke one of these
15
 * macros after, passing the function result(s) (_Py_ADJUST_ERANGE2 is useful
16
 * for functions returning complex results).  This makes two kinds of
17
 * adjustments to errno:  (A) If it looks like the platform libm set
18
 * errno=ERANGE due to underflow, clear errno. (B) If it looks like the
19
 * platform libm overflowed but didn't set errno, force errno to ERANGE.  In
20
 * effect, we're trying to force a useful implementation of C89 errno
21
 * behavior.
22
 * Caution:
23
 *    This isn't reliable.  C99 no longer requires libm to set errno under
24
 *        any exceptional condition, but does require +- HUGE_VAL return
25
 *        values on overflow.  A 754 box *probably* maps HUGE_VAL to a
26
 *        double infinity, and we're cool if that's so, unless the input
27
 *        was an infinity and an infinity is the expected result.  A C89
28
 *        system sets errno to ERANGE, so we check for that too.  We're
29
 *        out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or
30
 *        if the returned result is a NaN, or if a C89 box returns HUGE_VAL
31
 *        in non-overflow cases.
32
 */
33
static inline void _Py_ADJUST_ERANGE1(double x)
34
{
35
    if (errno == 0) {
  Branch (35:9): [True: 253k, False: 20]
36
        if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL) {
  Branch (36:13): [True: 0, False: 253k]
  Branch (36:33): [True: 0, False: 253k]
37
            errno = ERANGE;
38
        }
39
    }
40
    else if (errno == ERANGE && x == 0.0) {
  Branch (40:14): [True: 20, False: 0]
  Branch (40:33): [True: 20, False: 0]
41
        errno = 0;
42
    }
43
}
Unexecuted instantiation: complexobject.c:_Py_ADJUST_ERANGE1
floatobject.c:_Py_ADJUST_ERANGE1
Line
Count
Source
34
{
35
    if (errno == 0) {
  Branch (35:9): [True: 253k, False: 20]
36
        if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL) {
  Branch (36:13): [True: 0, False: 253k]
  Branch (36:33): [True: 0, False: 253k]
37
            errno = ERANGE;
38
        }
39
    }
40
    else if (errno == ERANGE && x == 0.0) {
  Branch (40:14): [True: 20, False: 0]
  Branch (40:33): [True: 20, False: 0]
41
        errno = 0;
42
    }
43
}
Unexecuted instantiation: pytime.c:_Py_ADJUST_ERANGE1
Unexecuted instantiation: sysmodule.c:_Py_ADJUST_ERANGE1
Unexecuted instantiation: pystrtod.c:_Py_ADJUST_ERANGE1
Unexecuted instantiation: dtoa.c:_Py_ADJUST_ERANGE1
44
45
static inline void _Py_ADJUST_ERANGE2(double x, double y)
46
{
47
    if (x == Py_HUGE_VAL || 
x == -225
Py_HUGE_VAL225
||
  Branch (47:9): [True: 21, False: 225]
  Branch (47:29): [True: 1, False: 224]
48
        
y == 224
Py_HUGE_VAL224
||
y == -221
Py_HUGE_VAL221
)
  Branch (48:9): [True: 3, False: 221]
  Branch (48:29): [True: 0, False: 221]
49
    {
50
        if (errno == 0) {
  Branch (50:13): [True: 6, False: 19]
51
            errno = ERANGE;
52
        }
53
    }
54
    else if (errno == ERANGE) {
  Branch (54:14): [True: 58, False: 163]
55
        errno = 0;
56
    }
57
}
complexobject.c:_Py_ADJUST_ERANGE2
Line
Count
Source
46
{
47
    if (x == Py_HUGE_VAL || 
x == -225
Py_HUGE_VAL225
||
  Branch (47:9): [True: 21, False: 225]
  Branch (47:29): [True: 1, False: 224]
48
        
y == 224
Py_HUGE_VAL224
||
y == -221
Py_HUGE_VAL221
)
  Branch (48:9): [True: 3, False: 221]
  Branch (48:29): [True: 0, False: 221]
49
    {
50
        if (errno == 0) {
  Branch (50:13): [True: 6, False: 19]
51
            errno = ERANGE;
52
        }
53
    }
54
    else if (errno == ERANGE) {
  Branch (54:14): [True: 58, False: 163]
55
        errno = 0;
56
    }
57
}
Unexecuted instantiation: floatobject.c:_Py_ADJUST_ERANGE2
Unexecuted instantiation: pytime.c:_Py_ADJUST_ERANGE2
Unexecuted instantiation: sysmodule.c:_Py_ADJUST_ERANGE2
Unexecuted instantiation: pystrtod.c:_Py_ADJUST_ERANGE2
Unexecuted instantiation: dtoa.c:_Py_ADJUST_ERANGE2
58
59
// Return the maximum value of integral type *type*.
60
#define _Py_IntegralTypeMax(type) \
61
    (
_Py_IS_TYPE_SIGNED375k
(type) ?
(((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1)375k
:
~(type)00
)
62
63
// Return the minimum value of integral type *type*.
64
#define _Py_IntegralTypeMin(type) \
65
    (_Py_IS_TYPE_SIGNED(type) ? -_Py_IntegralTypeMax(type) - 1 : 
00
)
66
67
// Check whether *v* is in the range of integral type *type*. This is most
68
// useful if *v* is floating-point, since demoting a floating-point *v* to an
69
// integral type that cannot represent *v*'s integral part is undefined
70
// behavior.
71
#define _Py_InIntegralTypeRange(type, v) \
72
    (_Py_IntegralTypeMin(type) <= v && 
v <= 187k
_Py_IntegralTypeMax187k
(type))
73
74
75
//--- HAVE_PY_SET_53BIT_PRECISION macro ------------------------------------
76
//
77
// The functions _Py_dg_strtod() and _Py_dg_dtoa() in Python/dtoa.c (which are
78
// required to support the short float repr introduced in Python 3.1) require
79
// that the floating-point unit that's being used for arithmetic operations on
80
// C doubles is set to use 53-bit precision.  It also requires that the FPU
81
// rounding mode is round-half-to-even, but that's less often an issue.
82
//
83
// If your FPU isn't already set to 53-bit precision/round-half-to-even, and
84
// you want to make use of _Py_dg_strtod() and _Py_dg_dtoa(), then you should:
85
//
86
//     #define HAVE_PY_SET_53BIT_PRECISION 1
87
//
88
// and also give appropriate definitions for the following three macros:
89
//
90
// * _Py_SET_53BIT_PRECISION_HEADER: any variable declarations needed to
91
//   use the two macros below.
92
// * _Py_SET_53BIT_PRECISION_START: store original FPU settings, and
93
//   set FPU to 53-bit precision/round-half-to-even
94
// * _Py_SET_53BIT_PRECISION_END: restore original FPU settings
95
//
96
// The macros are designed to be used within a single C function: see
97
// Python/pystrtod.c for an example of their use.
98
99
100
// Get and set x87 control word for gcc/x86
101
#ifdef HAVE_GCC_ASM_FOR_X87
102
#define HAVE_PY_SET_53BIT_PRECISION 1
103
104
// Functions defined in Python/pymath.c
105
extern unsigned short _Py_get_387controlword(void);
106
extern void _Py_set_387controlword(unsigned short);
107
108
#define _Py_SET_53BIT_PRECISION_HEADER                                  \
109
    unsigned short old_387controlword, new_387controlword
110
#define _Py_SET_53BIT_PRECISION_START                                   \
111
    do {                                                                \
112
        old_387controlword = _Py_get_387controlword();                  \
113
        new_387controlword = (old_387controlword & ~0x0f00) | 0x0200;   \
114
        if (new_387controlword != old_387controlword) {                 \
115
            _Py_set_387controlword(new_387controlword);                 \
116
        }                                                               \
117
    } while (0)
118
#define _Py_SET_53BIT_PRECISION_END                                     \
119
    do {                                                                \
120
        if (new_387controlword != old_387controlword) {                 \
121
            _Py_set_387controlword(old_387controlword);                 \
122
        }                                                               \
123
    } while (0)
124
#endif
125
126
// Get and set x87 control word for VisualStudio/x86.
127
// x87 is not supported in 64-bit or ARM.
128
#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_M_ARM)
129
#define HAVE_PY_SET_53BIT_PRECISION 1
130
131
#include <float.h>                // __control87_2()
132
133
#define _Py_SET_53BIT_PRECISION_HEADER \
134
    unsigned int old_387controlword, new_387controlword, out_387controlword
135
    // We use the __control87_2 function to set only the x87 control word.
136
    // The SSE control word is unaffected.
137
#define _Py_SET_53BIT_PRECISION_START                                   \
138
    do {                                                                \
139
        __control87_2(0, 0, &old_387controlword, NULL);                 \
140
        new_387controlword =                                            \
141
          (old_387controlword & ~(_MCW_PC | _MCW_RC)) | (_PC_53 | _RC_NEAR); \
142
        if (new_387controlword != old_387controlword) {                 \
143
            __control87_2(new_387controlword, _MCW_PC | _MCW_RC,        \
144
                          &out_387controlword, NULL);                   \
145
        }                                                               \
146
    } while (0)
147
#define _Py_SET_53BIT_PRECISION_END                                     \
148
    do {                                                                \
149
        if (new_387controlword != old_387controlword) {                 \
150
            __control87_2(old_387controlword, _MCW_PC | _MCW_RC,        \
151
                          &out_387controlword, NULL);                   \
152
        }                                                               \
153
    } while (0)
154
#endif
155
156
157
// MC68881
158
#ifdef HAVE_GCC_ASM_FOR_MC68881
159
#define HAVE_PY_SET_53BIT_PRECISION 1
160
#define _Py_SET_53BIT_PRECISION_HEADER \
161
    unsigned int old_fpcr, new_fpcr
162
#define _Py_SET_53BIT_PRECISION_START                                   \
163
    do {                                                                \
164
        __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr));                \
165
        /* Set double precision / round to nearest.  */                 \
166
        new_fpcr = (old_fpcr & ~0xf0) | 0x80;                           \
167
        if (new_fpcr != old_fpcr) {                                     \
168
              __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr));\
169
        }                                                               \
170
    } while (0)
171
#define _Py_SET_53BIT_PRECISION_END                                     \
172
    do {                                                                \
173
        if (new_fpcr != old_fpcr) {                                     \
174
            __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr));  \
175
        }                                                               \
176
    } while (0)
177
#endif
178
179
// Default definitions are empty
180
#ifndef _Py_SET_53BIT_PRECISION_HEADER
181
#  define _Py_SET_53BIT_PRECISION_HEADER
182
#  define _Py_SET_53BIT_PRECISION_START
183
#  define _Py_SET_53BIT_PRECISION_END
184
#endif
185
186
187
//--- _PY_SHORT_FLOAT_REPR macro -------------------------------------------
188
189
// If we can't guarantee 53-bit precision, don't use the code
190
// in Python/dtoa.c, but fall back to standard code.  This
191
// means that repr of a float will be long (17 significant digits).
192
//
193
// Realistically, there are two things that could go wrong:
194
//
195
// (1) doubles aren't IEEE 754 doubles, or
196
// (2) we're on x86 with the rounding precision set to 64-bits
197
//     (extended precision), and we don't know how to change
198
//     the rounding precision.
199
#if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \
200
    !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \
201
    !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
202
#  define _PY_SHORT_FLOAT_REPR 0
203
#endif
204
205
// Double rounding is symptomatic of use of extended precision on x86.
206
// If we're seeing double rounding, and we don't have any mechanism available
207
// for changing the FPU rounding precision, then don't use Python/dtoa.c.
208
#if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION)
209
#  define _PY_SHORT_FLOAT_REPR 0
210
#endif
211
212
#ifndef _PY_SHORT_FLOAT_REPR
213
#  define _PY_SHORT_FLOAT_REPR 1
214
#endif
215
216
217
#ifdef __cplusplus
218
}
219
#endif
220
#endif /* !Py_INTERNAL_PYMATH_H */