/*
 * MLFPE.C - SIGFPE routines for PML
 *
 * Source Version: 2.0
 * Software Release #92-0043
 *
 */

#include "cpyright.h"

#include "pml.h"

#ifdef AIX
# include <fptrap.h>
#endif

#ifdef SGI
# include <sigfpe.h>
#endif

#ifdef OSF

/* # include <machine/fpu.h> */
/* these are taken from <machine/fpu.h> which has illegal
 * constructs that render it uncompilable (@axposf.pa.dec.com)
 */
#define IEEE_TRAP_ENABLE_INV    0x000002   /* invalid operation */
#define IEEE_TRAP_ENABLE_DZE    0x000004   /* divide by 0 */
#define IEEE_TRAP_ENABLE_OVF    0x000008   /* overflow */

#endif

#ifdef SUN
# include <floatingpoint.h>
#endif

#ifdef SOLARIS
# ifndef __GNUC__
#  include <sunmath.h>
# endif
#endif

/* NOTE: SGI dramatically changed the API around IRIX 6.3
 *       The old argument was an unsigned long and the
 *       new is unsigned int **
 *       Both are advertised to be "a pointer to the address
 *       of the instruction which caused the exception"
 */

#ifdef SGI
# ifndef SGI_FPE_HAND_TYPE
#  define SGI_FPE_HAND_TYPE  unsigned int **
# endif
#endif

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_ENABLE_FPE - enable software trapping of floating point exceptions */

void PM_enable_fpe(flg, hand)
   int flg;
   PFSignal_handler hand;
   {

#ifdef SGI
#ifndef HAVE_NO_SIGFPE

    if (flg)
       {sigfpe_[_UNDERFL].repls = _ZERO;

	handle_sigfpes(_ON,
		       _EN_OVERFL | _EN_DIVZERO | _EN_INVALID,
		       NULL, _REPLACE_HANDLER_ON_ERROR,
		       (void (*)(SGI_FPE_HAND_TYPE)) hand);}
    else
       {handle_sigfpes(_OFF,
		       _EN_OVERFL | _EN_DIVZERO | _EN_INVALID,
		       NULL, _REPLACE_HANDLER_ON_ERROR,
		       (void (*)(SGI_FPE_HAND_TYPE)) hand);};
#endif
#endif

#ifdef AIX
    int ret;
    if (flg)
       {ret = fp_trap(FP_TRAP_FASTMODE);
        if (ret == FP_TRAP_ERROR)
           PRINT(stdout, "FP_TRAP CALLED WITH INVALID PARAMETER - PM_ENABLE_FPE");
        else if (ret == FP_TRAP_UNIMPL)
           PRINT(stdout, "FP_TRAP_FASTMODE NOT SUPPORTED - PM_ENABLE_FPE");
        fp_enable(TRP_INVALID |
	          TRP_DIV_BY_ZERO |
	          TRP_OVERFLOW);}
    else
       {ret = fp_trap(FP_TRAP_OFF);
        if (ret == FP_TRAP_ERROR)
           PRINT(stdout, "COULD NOT TURN OFF FPE TRAPPING - PM_ENABLE_FPE");
        fp_disable_all();};
#endif

#ifdef OSF
    {unsigned long ost, nst;

     ost = ieee_get_fp_control();
     if (flg)
        {nst = /* ost |  */
               IEEE_TRAP_ENABLE_INV |
               IEEE_TRAP_ENABLE_DZE |
               IEEE_TRAP_ENABLE_OVF;
         ieee_set_fp_control(nst);
         if (nst != ieee_get_fp_control())
            PRINT(stdout, "CAN'T SET FPE HANDLING - PM_ENABLE_FPE");}
     else
        {nst = /* ost &  */
               ~IEEE_TRAP_ENABLE_INV &
               ~IEEE_TRAP_ENABLE_DZE &
               ~IEEE_TRAP_ENABLE_OVF;
         ieee_set_fp_control(nst);
         if (nst != ieee_get_fp_control())
            PRINT(stdout, "CAN'T CLEAR FPE HANDLING - PM_ENABLE_FPE");};}
#endif

#ifdef SUN
    if (flg)
       {if (ieee_handler("set", "common", hand) != 0)
           PRINT(stdout, "CAN'T SET FPE HANDLING - PM_ENABLE_FPE");}
    else
       {if (ieee_handler("clear", "common", NULL) != 0)
           PRINT(stdout, "CAN'T CLEAR FPE HANDLING - PM_ENABLE_FPE");};
#endif

#ifdef SOLARIS
    if (flg)
       {nonstandard_arithmetic();
	if (ieee_handler("set", "common", hand) != 0)
           PRINT(stdout, "CAN'T SET FPE HANDLING - PM_ENABLE_FPE");}
    else
       {standard_arithmetic();
	if (ieee_handler("clear", "common", NULL) != 0)
           PRINT(stdout, "CAN'T CLEAR FPE HANDLING - PM_ENABLE_FPE");};
#endif

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
