1 /* $OpenBSD: setjmp-fpu.c,v 1.7 2021/06/17 12:55:38 kettenis Exp $ */
2
3 #include <err.h>
4 #include <fenv.h>
5 #include <setjmp.h>
6
7 int
TEST_SETJMP(void)8 TEST_SETJMP(void)
9 {
10 JMP_BUF env;
11 fexcept_t flag;
12 int rv;
13
14 /* Set up the FPU control word register. */
15 rv = fesetround(FE_UPWARD);
16 if (rv != 0)
17 errx(2, "fesetround FE_UPWARD returned %d", rv);
18 fedisableexcept(FE_ALL_EXCEPT);
19 feenableexcept(FE_DIVBYZERO);
20
21 rv = SETJMP(env, 0);
22
23 switch(rv) {
24 case 0: {
25 /* Mess with the FPU control word. */
26 rv = fesetround(FE_DOWNWARD);
27 if (rv != 0)
28 errx(2, "fesetround FE_DOWNWARD returned %d", rv);
29 fedisableexcept(FE_DIVBYZERO);
30
31 /* Set the FPU exception flags. */
32 flag = FE_OVERFLOW;
33 rv = fesetexceptflag(&flag, FE_ALL_EXCEPT);
34 if (rv != 0)
35 errx(2, "fesetexceptflag returned %d", rv);
36
37 LONGJMP(env, 1);
38 errx(2, "longjmp returned");
39 }
40 case 1: {
41 /* Verify that the FPU control word is preserved. */
42 rv = fegetround();
43 if (rv != FE_UPWARD)
44 errx(1, "fegetround returned %d, not FE_UPWARD", rv);
45 #if !defined(__arm__) && !defined(__aarch64__) && !defined(__riscv)
46 rv = fegetexcept();
47 if (rv != FE_DIVBYZERO)
48 errx(1, "fegetexcept returned %d, not FE_DIVBYZERO",
49 rv);
50 #endif
51
52 /* Verify that the FPU exception flags weren't clobbered. */
53 flag = 0;
54 rv = fegetexceptflag(&flag, FE_ALL_EXCEPT);
55 if (rv != 0)
56 errx(2, "fegetexceptflag returned %d", rv);
57 if (flag != FE_OVERFLOW)
58 errx(1, "except flag is %d, no FE_OVERFLOW", rv);
59
60 return (0);
61 }
62 default:
63 errx(2, "setjmp returned %d", rv);
64 }
65 }
66