1 /*	$OpenBSD: setjmp-fpu.c,v 1.5 2020/01/16 13:04:02 bluhm Exp $	*/
2 
3 #include <err.h>
4 #include <fenv.h>
5 #include <setjmp.h>
6 
7 int
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 		rv = fegetexcept();
46 		if (rv != FE_DIVBYZERO)
47 			errx(1, "fegetexcept returned %d, not FE_DIVBYZERO",
48 			    rv);
49 
50 		/* Verify that the FPU exception flags weren't clobbered. */
51 		flag = 0;
52 		rv = fegetexceptflag(&flag, FE_ALL_EXCEPT);
53 		if (rv != 0)
54 			errx(2, "fegetexceptflag returned %d", rv);
55 		if (flag != FE_OVERFLOW)
56 			errx(1, "except flag is %d, no FE_OVERFLOW", rv);
57 
58 		return (0);
59 	}
60 	default:
61 		errx(2, "setjmp returned %d", rv);
62 	}
63 }
64