about summary refs log tree commit diff
path: root/sysdeps/sparc/fpu/fenv_private.h
blob: da7c7fe332f54895f49aed62be4de0957629c510 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#ifndef SPARC_FENV_PRIVATE_H
#define SPARC_FENV_PRIVATE_H 1

#include <fenv.h>

/* For internal use only: access the fp state register.  */
#if __WORDSIZE == 64
# define __fenv_stfsr(X)   __asm__ __volatile__ ("stx %%fsr,%0" : "=m" (X))
# define __fenv_ldfsr(X)   __asm__ __volatile__ ("ldx %0,%%fsr" : : "m" (X))
#else
# define __fenv_stfsr(X)   __asm__ __volatile__ ("st %%fsr,%0" : "=m" (X))
# define __fenv_ldfsr(X)   __asm__ __volatile__ ("ld %0,%%fsr" : : "m" (X))
#endif

static __always_inline void
libc_feholdexcept (fenv_t *e)
{
  fenv_t etmp;
  __fenv_stfsr(etmp);
  *(e) = etmp;
  etmp = etmp & ~((0x1f << 23) | FE_ALL_EXCEPT);
  __fenv_ldfsr(etmp);
}

static __always_inline void
libc_fesetround (int r)
{
  fenv_t etmp;
  __fenv_stfsr(etmp);
  etmp = (etmp & ~__FE_ROUND_MASK) | (r);
  __fenv_ldfsr(etmp);
}

static __always_inline void
libc_feholdexcept_setround (fenv_t *e, int r)
{
  fenv_t etmp;
  __fenv_stfsr(etmp);
  *(e) = etmp;
  etmp = etmp & ~((0x1f << 23) | FE_ALL_EXCEPT);
  etmp = (etmp & ~__FE_ROUND_MASK) | (r);
  __fenv_ldfsr(etmp);
}

static __always_inline int
libc_fetestexcept (int e)
{
  fenv_t etmp;
  __fenv_stfsr(etmp);
  return etmp & (e) & FE_ALL_EXCEPT;
}

static __always_inline void
libc_fesetenv (fenv_t *e)
{
  __fenv_ldfsr(*e);
}

static __always_inline int
libc_feupdateenv_test (fenv_t *e, int ex)
{
  fenv_t etmp;

  __fenv_stfsr(etmp);
  etmp &= FE_ALL_EXCEPT;

  __fenv_ldfsr(*e);

  __feraiseexcept (etmp);

  return etmp & ex;
}

static __always_inline void
libc_feupdateenv (fenv_t *e)
{
  libc_feupdateenv_test (e, 0);
}

static __always_inline void
libc_feholdsetround (fenv_t *e, int r)
{
  fenv_t etmp;
  __fenv_stfsr(etmp);
  *(e) = etmp;
  etmp = (etmp & ~__FE_ROUND_MASK) | (r);
  __fenv_ldfsr(etmp);
}

static __always_inline void
libc_feresetround (fenv_t *e)
{
  fenv_t etmp;
  __fenv_stfsr(etmp);
  etmp = (etmp & ~__FE_ROUND_MASK) | (*e & __FE_ROUND_MASK);
  __fenv_ldfsr(etmp);
}

#define libc_feholdexceptf		libc_feholdexcept
#define libc_fesetroundf		libc_fesetround
#define libc_feholdexcept_setroundf	libc_feholdexcept_setround
#define libc_fetestexceptf		libc_fetestexcept
#define libc_fesetenvf			libc_fesetenv
#define libc_feupdateenv_testf		libc_feupdateenv_test
#define libc_feupdateenvf		libc_feupdateenv
#define libc_feholdsetroundf		libc_feholdsetround
#define libc_feresetroundf		libc_feresetround
#define libc_feholdexcept		libc_feholdexcept
#define libc_fesetround			libc_fesetround
#define libc_feholdexcept_setround	libc_feholdexcept_setround
#define libc_fetestexcept		libc_fetestexcept
#define libc_fesetenv			libc_fesetenv
#define libc_feupdateenv_test		libc_feupdateenv_test
#define libc_feupdateenv		libc_feupdateenv
#define libc_feholdsetround		libc_feholdsetround
#define libc_feresetround		libc_feresetround
#define libc_feholdexceptl		libc_feholdexcept
#define libc_fesetroundl		libc_fesetround
#define libc_feholdexcept_setroundl	libc_feholdexcept_setround
#define libc_fetestexceptl		libc_fetestexcept
#define libc_fesetenvl			libc_fesetenv
#define libc_feupdateenv_testl		libc_feupdateenv_test
#define libc_feupdateenvl		libc_feupdateenv
#define libc_feholdsetroundl		libc_feholdsetround
#define libc_feresetroundl		libc_feresetround

/* We have support for rounding mode context.  */
#define HAVE_RM_CTX 1

static __always_inline void
libc_feholdexcept_setround_sparc_ctx (struct rm_ctx *ctx, int round)
{
  fenv_t new;

  __fenv_stfsr(ctx->env);
  new = ctx->env & ~((0x1f << 23) | FE_ALL_EXCEPT);
  new = (new & ~__FE_ROUND_MASK) | round;
  if (__glibc_unlikely (new != ctx->env))
    {
      __fenv_ldfsr(new);
      ctx->updated_status = true;
    }
  else
    ctx->updated_status = false;
}

static __always_inline void
libc_fesetenv_sparc_ctx (struct rm_ctx *ctx)
{
  libc_fesetenv(&ctx->env);
}

static __always_inline void
libc_feupdateenv_sparc_ctx (struct rm_ctx *ctx)
{
  if (__glibc_unlikely (ctx->updated_status))
    libc_feupdateenv_test (&ctx->env, 0);
}

static __always_inline void
libc_feholdsetround_sparc_ctx (struct rm_ctx *ctx, int round)
{
  fenv_t new;

  __fenv_stfsr(ctx->env);
  new = (ctx->env & ~__FE_ROUND_MASK) | round;
  if (__glibc_unlikely (new != ctx->env))
    {
      __fenv_ldfsr(new);
      ctx->updated_status = true;
    }
  else
    ctx->updated_status = false;
}
#define libc_feholdexcept_setround_ctx   libc_feholdexcept_setround_sparc_ctx
#define libc_feholdexcept_setroundf_ctx  libc_feholdexcept_setround_sparc_ctx
#define libc_feholdexcept_setroundl_ctx  libc_feholdexcept_setround_sparc_ctx
#define libc_fesetenv_ctx                libc_fesetenv_sparc_ctx
#define libc_fesetenvf_ctx               libc_fesetenv_sparc_ctx
#define libc_fesetenvl_ctx               libc_fesetenv_sparc_ctx
#define libc_feupdateenv_ctx             libc_feupdateenv_sparc_ctx
#define libc_feupdateenvf_ctx            libc_feupdateenv_sparc_ctx
#define libc_feupdateenvl_ctx            libc_feupdateenv_sparc_ctx
#define libc_feresetround_ctx            libc_feupdateenv_sparc_ctx
#define libc_feresetroundf_ctx           libc_feupdateenv_sparc_ctx
#define libc_feresetroundl_ctx           libc_feupdateenv_sparc_ctx
#define libc_feholdsetround_ctx          libc_feholdsetround_sparc_ctx
#define libc_feholdsetroundf_ctx         libc_feholdsetround_sparc_ctx
#define libc_feholdsetroundl_ctx         libc_feholdsetround_sparc_ctx

#include_next <fenv_private.h>

#endif /* SPARC_FENV_PRIVATE_H */