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
7int
8TEST_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