Ticket #19063: foo2.c

File foo2.c, 2.3 KB (added by bhaible, 2 months ago)

test case foo2.c

Line 
1#include <assert.h>
2#include <fenv.h>
3#include <stdio.h>
4
5typedef struct
6 {
7 unsigned short __control_word;
8 unsigned short __reserved1;
9 unsigned short __status_word;
10 unsigned short __reserved2;
11 unsigned int more[5];
12 }
13x86_387_fenv_t;
14
15int
16feenableexcept (int exceptions)
17{
18 exceptions &= 0x3f;
19
20 /* Enable the traps in the 387 unit. */
21 unsigned short fctrl, orig_fctrl;
22 __asm__ __volatile__ ("fnstcw %0" : "=m" (*&orig_fctrl));
23 fctrl = orig_fctrl & ~exceptions;
24 if (fctrl != orig_fctrl)
25 __asm__ __volatile__ ("fldcw %0" : : "m" (*&fctrl));
26
27 if (1)
28 {
29 /* Enable the traps in the SSE unit as well. */
30 unsigned int mxcsr, orig_mxcsr;
31 __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&orig_mxcsr));
32 mxcsr = orig_mxcsr & ~(exceptions << 7);
33 if (mxcsr != orig_mxcsr)
34 __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr));
35 }
36
37 return 0x3f & ~orig_fctrl;
38}
39
40static int
41sigfpe_on_invalid ()
42{
43 /* Clear FE_INVALID exceptions from past operations. */
44 feclearexcept (FE_INVALID);
45
46 /* An FE_INVALID exception shall trigger a SIGFPE signal.
47 This call may fail on arm, arm64, riscv64 CPUs.
48 Also, possibly a bug in glibc/sysdeps/m68k/fpu/feenablxcpt.c: it sets
49 only bit 13, but should better set bits 15, 14, 13 of the control
50 register together. See
51 <https://sourceware.org/bugzilla/show_bug.cgi?id=30993>. */
52 int ret = feenableexcept (FE_INVALID);
53 if (ret == -1)
54 return -1;
55
56 return 0;
57}
58
59/* Test that feupdateenv(), unlike fesetenv(), can trigger traps. */
60
61int
62main ()
63{
64 fenv_t env1;
65
66 /* Get to a known initial state. */
67 assert (feclearexcept (0x3f) == 0);
68
69 /* Enable trapping on FE_INVALID. */
70 if (sigfpe_on_invalid () < 0)
71 {
72 fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
73 return 77;
74 }
75
76 /* Save the current environment in env1. */
77 assert (fegetenv (&env1) == 0);
78
79 /* Go back to the default environment. */
80 assert (fesetenv (FE_DFL_ENV) == 0);
81
82 /* Modify the current environment. */
83 assert (feraiseexcept (FE_INVALID) == 0);
84
85 /* Go back to env1.
86 Since the exceptions flag FE_INVALID is currently set, and since
87 env1 has trapping on FE_INVALID enabled, this should trap. */
88 assert (feupdateenv (&env1) == 0);
89
90 return 0;
91}