1/*
2 * Copyright (c) 2005-2019 Rich Felker, et al.
3 *
4 * Part of MUSL, released under the MIT license.
5 */
6
7
8#include <fenv.h>
9#include <features.h>
10
11#define hidden __attribute__((__visibility__("hidden")))
12
13#if __HAVE_68881__ || __mcffpu__
14
15static unsigned getsr()
16{
17	unsigned v;
18	__asm__ __volatile__ ("fmove.l %%fpsr,%0" : "=dm"(v));
19	return v;
20}
21
22static void setsr(unsigned v)
23{
24	__asm__ __volatile__ ("fmove.l %0,%%fpsr" : : "dm"(v));
25}
26
27static unsigned getcr()
28{
29	unsigned v;
30	__asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=dm"(v));
31	return v;
32}
33
34static void setcr(unsigned v)
35{
36	__asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "dm"(v));
37}
38
39int feclearexcept(int mask)
40{
41	if (mask & ~FE_ALL_EXCEPT) return -1;
42	setsr(getsr() & ~mask);
43	return 0;
44}
45
46int feraiseexcept(int mask)
47{
48	if (mask & ~FE_ALL_EXCEPT) return -1;
49	setsr(getsr() | mask);
50	return 0;
51}
52
53int fetestexcept(int mask)
54{
55	return getsr() & mask;
56}
57
58int fegetround(void)
59{
60	return getcr() & FE_UPWARD;
61}
62
63hidden int __fesetround(int r)
64{
65	setcr((getcr() & ~FE_UPWARD) | r);
66	return 0;
67}
68
69int fegetenv(fenv_t *envp)
70{
71	envp->__control_register = getcr();
72	envp->__status_register = getsr();
73	__asm__ __volatile__ ("fmove.l %%fpiar,%0"
74		: "=dm"(envp->__instruction_address));
75	return 0;
76}
77
78int fesetenv(const fenv_t *envp)
79{
80	static const fenv_t default_env = { 0 };
81	if (envp == FE_DFL_ENV)
82		envp = &default_env;
83	setcr(envp->__control_register);
84	setsr(envp->__status_register);
85	__asm__ __volatile__ ("fmove.l %0,%%fpiar"
86		: : "dm"(envp->__instruction_address));
87	return 0;
88}
89
90#else
91
92#include "fenv-generic.c"
93
94#endif
95