~ubuntu-branches/ubuntu/karmic/python-scipy/karmic

« back to all changes in this revision

Viewing changes to Lib/xplt/src/play/unix/fpuset.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T. Chen (new)
  • Date: 2005-03-16 02:15:29 UTC
  • Revision ID: james.westby@ubuntu.com-20050316021529-xrjlowsejs0cijig
Tags: upstream-0.3.2
ImportĀ upstreamĀ versionĀ 0.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * fpuset.c -- $Id: fpuset.c,v 1.1 2003/03/08 15:26:48 travo Exp $
 
3
 * set up FPU to trap floating point exceptions
 
4
 * - this is very non-portable, not covered by ANSI C, POSIX, or even C9X
 
5
 * - if you port to a new platform (eg- Ultrix) please contact the author
 
6
 *
 
7
 * Copyright (c) 1999.  See accompanying LEGAL file for details.
 
8
 */
 
9
 
 
10
#ifndef FROM_FPUTEST
 
11
# include "config.h"
 
12
# include "playu.h"
 
13
#else
 
14
extern void u_fpu_setup(int when);
 
15
#endif
 
16
 
 
17
/* when = -1 for initial call before setjmp
 
18
 *         0 after each longjmp out of interrupt handler (after setjmp)
 
19
 *         1 inside interrupt handler before signal() re-enables SIGFPE
 
20
 */
 
21
 
 
22
#if defined(FPU_DIGITAL) || defined(FPU_ALPHA_LINUX)
 
23
 
 
24
/* FPU_ALPHA_LINUX: see README.fpu */
 
25
/* man pages: exception_intro, ieee */
 
26
# ifdef FPU_DIGITAL
 
27
#  include <machine/fpu.h>
 
28
# else
 
29
   extern void ieee_set_fp_control(long);
 
30
#  define IEEE_TRAP_ENABLE_INV 0x000002
 
31
#  define IEEE_TRAP_ENABLE_DZE 0x000004
 
32
#  define IEEE_TRAP_ENABLE_OVF 0x000008
 
33
#  define IEEE_MAP_DMZ         (1UL<<12)
 
34
#  define IEEE_MAP_UMZ         (1UL<<13)
 
35
# endif
 
36
void
 
37
u_fpu_setup(int when)
 
38
{
 
39
  /* possibly should include IEEE_MAP_DMZ and IEEE_MAP_UMZ
 
40
   * to map denorm inputs and underflowed outputs to zero
 
41
   * --however, these apparently only have an effect for software
 
42
   * completed operations (the hardware always maps underflows to zero)
 
43
   */
 
44
  if (when < 0) {
 
45
    ieee_set_fp_control(IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |
 
46
                        IEEE_TRAP_ENABLE_OVF);
 
47
  }
 
48
}
 
49
 
 
50
#elif defined(FPU_AIX)
 
51
 
 
52
/* man pages: fp_trap, fp_enable */
 
53
#include <fptrap.h>
 
54
void
 
55
u_fpu_setup(int when)
 
56
{
 
57
  if (when) {
 
58
    fp_trap(FP_TRAP_FASTMODE);
 
59
    fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
 
60
  }
 
61
}
 
62
 
 
63
#elif defined(FPU_HPUX)
 
64
 
 
65
/* man pages: fpsetmask
 
66
 * library: -lm */
 
67
/* HPUX turns off FP_X_* without this (_INCLUDE_HPUX_SOURCE) */
 
68
#ifndef _HPUX_SOURCE
 
69
#define _HPUX_SOURCE 1
 
70
#endif
 
71
#include <math.h>
 
72
void
 
73
u_fpu_setup(int when)
 
74
{
 
75
  if (when <= 0) {
 
76
    fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL);  /* 0x1c */
 
77
    fpsetfastmode(1);    /* fast underflows */
 
78
  }
 
79
}
 
80
 
 
81
#elif defined(FPU_IRIX)
 
82
 
 
83
/* man pages: handle_sigfpes, note lethal TRAP_FPE environment variable
 
84
 * library: -lfpe
 
85
 * note: earlier versions used get_fpc_csr/set_fpc_csr?, sys/fpu.h */
 
86
#include <sigfpe.h>
 
87
void
 
88
u_fpu_setup(int when)
 
89
{
 
90
  if (when < 0) {
 
91
    extern void u_sigfpe(int sig);  /* from handler.c (or fputest.c) */
 
92
    handle_sigfpes(_ON, _EN_OVERFL|_EN_DIVZERO|_EN_INVALID,
 
93
                   (void (*)())0, _USER_HANDLER, (void (*)())&u_sigfpe);
 
94
  }
 
95
}
 
96
 
 
97
#elif defined(FPU_SOLARIS)
 
98
 
 
99
/* man pages: fpsetmask
 
100
 *    Sun's -fnonstd compiler switch switches between __fnonstd.o
 
101
 *      and __fstd.o under Solaris, as far as I can tell.  Use FPU_IGNORE
 
102
 *        if you do this.  */
 
103
#include <ieeefp.h>
 
104
void
 
105
u_fpu_setup(int when)
 
106
{
 
107
  if (when < 0) {
 
108
    fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL);
 
109
    /* this doesn't set the "nonstandard arithmetic" bit, which prevents
 
110
     * software emulation of IEEE gradual underflow
 
111
     * -- apparently no way to do this in libc (see FPU_GCC_SPARC) */
 
112
  }
 
113
}
 
114
 
 
115
#elif defined(FPU_SUN4)
 
116
 
 
117
/* man pages: ieee_handler
 
118
 *               nonstandard_arithmetic is undocumented, but rumored
 
119
 *               to be important to get rapid underflows
 
120
 * library: -lsunmath (under /usr/lang hierarchy)
 
121
 *          may also be in -lm (standard libm)?
 
122
 *   note: libsunmath.a is provided by Sun only if you purchase their
 
123
 *         compilers; if you are trying to compile with gcc on a SPARC
 
124
 *         architecture, try FPU_GCC_SPARC
 
125
 *    Sun's -fnonstd compiler switch buggers crt1.o under SunOS 4,
 
126
 *      as far as I can tell.  Use FPU_IGNORE if you do this
 
127
 *      (not possible with gcc?).  */
 
128
void
 
129
u_fpu_setup(int when)
 
130
{
 
131
  if (when < 0) {
 
132
    extern void u_sigfpe(int sig);  /* from handler.c (or fputest.c) */
 
133
    nonstandard_arithmetic();
 
134
    ieee_handler("set","common", &u_sigfpe);
 
135
  }
 
136
}
 
137
 
 
138
#elif defined(FPU_UNICOS)
 
139
 
 
140
/* delivers SIGFPE by default, this just arranges to trap on
 
141
 * libm errors as well */
 
142
void
 
143
u_fpu_setup(int when)
 
144
{
 
145
  if (when < 0) {
 
146
    int flag = -1;
 
147
    libmset(&flag);
 
148
  }
 
149
}
 
150
 
 
151
#elif defined(FPU_GNU_FENV)
 
152
 
 
153
/* GCC enhanced C9X fenv.h interface by adding feenableexcept */
 
154
#include <fenv.h>
 
155
void
 
156
u_fpu_setup(int when)
 
157
{
 
158
  if (when <= 0)
 
159
    feenableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID);
 
160
}
 
161
 
 
162
#elif defined(FPU_GCC_I86)
 
163
 
 
164
/* see also: fpu_control.h or i386/fpu_control.h, __setfpucw function */
 
165
void
 
166
u_fpu_setup(int when)
 
167
{
 
168
  if (when) {
 
169
    unsigned int fpucw = 0x1372;
 
170
    __asm__ ("fldcw %0" : : "m" (fpucw));
 
171
  }
 
172
}
 
173
 
 
174
#elif defined(FPU_GCC_POWERPC)
 
175
 
 
176
void
 
177
u_fpu_setup(int when)
 
178
{
 
179
  if (when) {
 
180
    unsigned int tmp[2] __attribute__ ((__aligned__(8)));
 
181
    tmp[0] = 0xFFF80000; /* More-or-less arbitrary; this is a QNaN. */
 
182
    tmp[1] = 0xd0;
 
183
    __asm__ ("lfd 0,%0; mtfsf 255,0" : : "m" (*tmp) : "fr0");
 
184
  }
 
185
}
 
186
 
 
187
#elif defined(FPU_GCC_SPARC)
 
188
 
 
189
void
 
190
u_fpu_setup(int when)
 
191
{
 
192
  if (when < 0) {
 
193
    unsigned int fpucw = 0xd400000;  /* the 4 is nonstandard arithmetic bit */
 
194
    __asm__ ("ld %0,%%fsr" : : "m" (fpucw));
 
195
  }
 
196
}
 
197
 
 
198
#elif defined(FPU_GCC_M68K)
 
199
 
 
200
/* works on NeXT as well as m68k Linux */
 
201
void
 
202
u_fpu_setup(int when)
 
203
{
 
204
  if (when <= 0) {
 
205
    asm("fmovel     #0x7400,fpcr");   /* set OVFL and ZD bits */
 
206
    /* unsigned int fpucw = 0x7400;
 
207
     * __asm__ volatile ("fmove%.l %0, %!" : : "dm" (fpucw)); */
 
208
    /* includes bit to trap on signalling NaN (may affect libm behavior) */
 
209
  }
 
210
}
 
211
 
 
212
#elif defined(FPU_GCC_ARM)
 
213
 
 
214
void
 
215
u_fpu_setup(int when)
 
216
{
 
217
  if (when <= 0) {
 
218
    unsigned int fpucw = 0x70200;
 
219
    __asm__ ("wfs %0" : : "r" (fpucw));
 
220
    /* includes bit to trap on signalling NaN (may affect libm behavior) */
 
221
  }
 
222
}
 
223
 
 
224
#elif defined(FPU_IGNORE)
 
225
 
 
226
void
 
227
u_fpu_setup(int when)
 
228
{
 
229
}
 
230
 
 
231
#elif defined(FPU_MACOSX)
 
232
 
 
233
#include <architecture/ppc/fp_regs.h>
 
234
#include <mach/mach.h>
 
235
#include <pthread.h>
 
236
 
 
237
static void *fpu_fpe_enable(void *arg);
 
238
#define FE0_MASK (1<<11)
 
239
#define FE1_MASK (1<<8)
 
240
/* FE0  FE1   exceptions enabled if either FE0 or FE1 set
 
241
 *  0    0    -- floating-point exceptions disabled
 
242
 *  0    1    -- floating-point imprecise nonrecoverable
 
243
 *  1    0    -- floating-point imprecise recoverable
 
244
 *  1    1    -- floating-point precise mode
 
245
 */
 
246
/* for Darwin version 6.0 (MacOS X 10.2) FE0=FE1=1 initially
 
247
 * for Darwin version 5.5 (MacOS X <=10.1) FE0=FE1=0 initially
 
248
 * Darwin 5.5 resets MSR to FE0=FE1=0 after each SIGFPE
 
249
 * Darwin 6.0 does not reset MSR?  leave MSR reset code in case?
 
250
 */
 
251
 
 
252
/* a thread cannot get or set its own MSR bits */
 
253
static void *
 
254
fpu_fpe_enable(void *arg)
 
255
{
 
256
  thread_t t = *(thread_t *)arg;
 
257
  struct ppc_thread_state state;
 
258
  unsigned int state_size = PPC_THREAD_STATE_COUNT;
 
259
  if (thread_get_state(t, PPC_THREAD_STATE,
 
260
                       (natural_t *)&state, &state_size) == KERN_SUCCESS) {
 
261
    state.srr1 |= FE1_MASK;
 
262
    state.srr1 &= ~FE0_MASK;
 
263
    thread_set_state(t, PPC_THREAD_STATE, (natural_t *)&state, state_size);
 
264
  }
 
265
  return 0;
 
266
}
 
267
 
 
268
void
 
269
u_fpu_setup(int when)
 
270
{
 
271
  static volatile int looping = 0;
 
272
  if (when) {
 
273
    ppc_fp_scr_t r = get_fp_scr();
 
274
    /* turn off exception bits to prevent immediate re-fault */
 
275
    r.fx = r.fex = r.vx = r.ox = r.ux = r.zx = r.xx = r.vx_snan = r.vx_isi =
 
276
      r.vx_idi = r.vx_zdz = r.vx_imz = r.vx_xvc = r.vx_cvi = r.vx_soft = 0;
 
277
    /* these only have to be set once, but may as well set anyway */
 
278
    r.ve = 1;  /* invalid */
 
279
    r.oe = 1;  /* overflow */
 
280
    r.ue = 0;  /* underflow */
 
281
    r.ze = 1;  /* zero divide */
 
282
    r.xe = 0;  /* inexact */
 
283
    if (!looping) {
 
284
      looping |= 1;
 
285
      set_fp_scr(r);
 
286
      looping &= ~1;
 
287
    }
 
288
  }
 
289
  if (when <= 0) {
 
290
    thread_t self = mach_thread_self();
 
291
    pthread_t enabler;
 
292
    if (!looping) {
 
293
      looping |= 2;
 
294
      if (!pthread_create(&enabler, 0, fpu_fpe_enable, &self))
 
295
        pthread_join(enabler, 0);
 
296
      looping &= ~2;
 
297
    }
 
298
  }
 
299
  looping = 0;
 
300
}
 
301
 
 
302
#else
 
303
 
 
304
#error <read play/unix/README.fpu for help>
 
305
 
 
306
#endif