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
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