xref: /csrg-svn/usr.bin/f77/libF77/trpfpe_.c (revision 14635)
113576Sdlw /* #define	OLD_BSD		if you're running < 4.2bsd */
213576Sdlw /*
3*14635Sdlw char	id_trpfpe[] = "@(#)trpfpe_.c	1.3";
413576Sdlw  *
513576Sdlw  *	Fortran floating-point error handler
613576Sdlw  *
713576Sdlw  *	Synopsis:
813576Sdlw  *		call trpfpe (n, retval)
913576Sdlw  *			causes floating point faults to be trapped, with the
1013576Sdlw  *			first 'n' errors getting a message printed.
1113576Sdlw  *			'retval' is put in place of the bad result.
1213576Sdlw  *		k = fpecnt()
1313576Sdlw  *			causes 'k' to get the number of errors since the
1413576Sdlw  *			last call to trpfpe().
1513576Sdlw  *
1613576Sdlw  *		common /fpeflt/ fpflag
1713576Sdlw  *		logical fpflag
1813576Sdlw  *			fpflag will become .true. on faults
1913576Sdlw  *
2013576Sdlw  *	David Wasley, UCBerkeley, June 1983.
2113576Sdlw  */
2213576Sdlw 
2313576Sdlw 
2413576Sdlw #include <stdio.h>
2513576Sdlw #include <signal.h>
2613576Sdlw #include "opcodes.h"
2713576Sdlw #include "operand.h"
2813576Sdlw #include "../libI77/fiodefs.h"
2913576Sdlw 
3013576Sdlw #define	SIG_VAL		int (*)()
3113576Sdlw 
3213576Sdlw #if	vax		/* only works on VAXen */
3313576Sdlw 
3413576Sdlw struct arglist {		/* what AP points to */
3513576Sdlw 	long	al_numarg;	/* only true in CALLS format */
3613576Sdlw 	long	al_arg[256];
3713576Sdlw };
3813576Sdlw 
3913576Sdlw struct cframe {			/* VAX call frame */
4013576Sdlw 	long		cf_handler;
4113576Sdlw 	unsigned short	cf_psw;
4213576Sdlw 	unsigned short	cf_mask;
4313576Sdlw 	struct arglist	*cf_ap;
4413576Sdlw 	struct cframe	*cf_fp;
4513576Sdlw 	char		*cf_pc;
4613576Sdlw };
4713576Sdlw 
4813576Sdlw /*
4913576Sdlw  * bits in the PSW
5013576Sdlw  */
5113576Sdlw #define	PSW_V	0x2
5213576Sdlw #define	PSW_FU	0x40
5313576Sdlw #define	PSW_IV	0x20
5413576Sdlw 
5513576Sdlw /*
5613576Sdlw  * where the registers are stored as we see them in the handler
5713576Sdlw  */
5813576Sdlw struct reg0_6 {
5913576Sdlw 	long	reg[7];
6013576Sdlw };
6113576Sdlw 
6213576Sdlw struct reg7_11 {
6313576Sdlw 	long	reg[5];
6413576Sdlw };
6513576Sdlw 
6613576Sdlw #define	iR0	reg0_6->reg[0]
6713576Sdlw #define	iR1	reg0_6->reg[1]
6813576Sdlw #define	iR2	reg0_6->reg[2]
6913576Sdlw #define	iR3	reg0_6->reg[3]
7013576Sdlw #define	iR4	reg0_6->reg[4]
7113576Sdlw #define	iR5	reg0_6->reg[5]
7213576Sdlw #define	iR6	reg0_6->reg[6]
7313576Sdlw #define	iR7	reg7_11->reg[0]
7413576Sdlw #define	iR8	reg7_11->reg[1]
7513576Sdlw #define	iR9	reg7_11->reg[2]
7613576Sdlw #define	iR10	reg7_11->reg[3]
7713576Sdlw #define	iR11	reg7_11->reg[4]
7813576Sdlw 
7913576Sdlw union objects {		/* for load/store */
8013576Sdlw 	char	ua_byte;
8113576Sdlw 	short	ua_word;
8213576Sdlw 	long	ua_long;
8313576Sdlw 	float	ua_float;
8413576Sdlw 	double	ua_double;
8513576Sdlw 	union objects	*ua_anything;
8613576Sdlw };
8713576Sdlw 
8813576Sdlw typedef union objects	anything;
8913576Sdlw enum object_type { BYTE, WORD, LONG, FLOAT, QUAD, DOUBLE, UNKNOWN };
9013576Sdlw 
9113576Sdlw 
9213576Sdlw /*
9313576Sdlw  * assembly language assist
9413576Sdlw  * There are some things you just can't do in C
9513576Sdlw  */
9613576Sdlw asm(".text");
9713576Sdlw 
9813576Sdlw struct cframe	*myfp();
9913576Sdlw asm("_myfp: .word 0x0");
10013576Sdlw 	asm("movl 12(fp),r0");
10113576Sdlw 	asm("ret");
10213576Sdlw 
10313576Sdlw struct arglist	*myap();
10413576Sdlw asm("_myap: .word 0x0");
10513576Sdlw 	asm("movl 8(fp),r0");
10613576Sdlw 	asm("ret");
10713576Sdlw 
10813576Sdlw char	*mysp();
10913576Sdlw asm("_mysp: .word 0x0");
11013576Sdlw 	asm("extzv $30,$2,4(fp),r0");
11113576Sdlw 	asm("addl2 ap,r0");	/* SP in caller is AP+4 here + SPA bits! */
11213576Sdlw 	asm("addl2 $4,r0");
11313576Sdlw 	asm("ret");
11413576Sdlw 
11513576Sdlw char	*mypc();
11613576Sdlw asm("_mypc: .word 0x0");
11713576Sdlw 	asm("movl 16(fp),r0");
11813576Sdlw 	asm("ret");
11913576Sdlw 
12013576Sdlw asm(".data");
12113576Sdlw 
12213576Sdlw 
12313576Sdlw /*
12413576Sdlw  * Where interrupted objects are
12513576Sdlw  */
12613576Sdlw static struct cframe	**ifp;	/* addr of saved FP */
12713576Sdlw static struct arglist	**iap;	/* addr of saved AP */
12813576Sdlw static char		 *isp;	/* value of interrupted SP */
12913576Sdlw static char		**ipc;	/* addr of saved PC */
13013576Sdlw static struct reg0_6	*reg0_6;/* registers 0-6 are saved on the exception */
13113576Sdlw static struct reg7_11	*reg7_11;/* we save 7-11 by our entry mask */
13213576Sdlw static anything		*result_addr;	/* where the dummy result goes */
13313576Sdlw static enum object_type	 result_type;	/* what kind of object it is */
13413576Sdlw 
13513576Sdlw /*
13613576Sdlw  * some globals
13713576Sdlw  */
13813576Sdlw static union {
13913576Sdlw 	long	rv_long[2];
14013576Sdlw 	float	rv_float;
14113576Sdlw 	double	rv_double;
14213576Sdlw 			} retval; /* the user specified dummy result */
14313576Sdlw static int	max_messages	= 1;		/* the user can tell us */
14413576Sdlw static int	fpe_count	= 0;		/* how bad is it ? */
14513576Sdlw        long	fpeflt_		= 0;	/* fortran "common /fpeflt/ flag" */
14613576Sdlw static int	(*sigfpe_dfl)()	= SIG_DFL;	/* if we can't fix it ... */
14713576Sdlw 
14813576Sdlw /*
14913576Sdlw  * The fortran unit control table
15013576Sdlw  */
15113576Sdlw extern unit units[];
15213576Sdlw 
15313576Sdlw /*
15413576Sdlw  * Fortran message table is in main
15513576Sdlw  */
15613576Sdlw struct msgtbl {
15713576Sdlw 	char	*mesg;
15813576Sdlw 	int	dummy;
15913576Sdlw };
16013576Sdlw extern struct msgtbl	act_fpe[];
16113576Sdlw 
16213576Sdlw 
16313576Sdlw /*
16413576Sdlw  * Get the address of the (saved) next operand & update saved PC.
16513576Sdlw  * The major purpose of this is to determine where to store the result.
16613576Sdlw  * There is one case we can't deal with: -(SP) or (SP)+
16713576Sdlw  * since we can't change the size of the stack.
16813576Sdlw  * Let's just hope compilers don't generate that for results.
16913576Sdlw  */
17013576Sdlw 
17113576Sdlw anything *
17213576Sdlw get_operand (oper_size)
17313576Sdlw 	int	oper_size;	/* size of operand we expect */
17413576Sdlw {
17513576Sdlw 	register int	regnum;
17613576Sdlw 	register int	operand_code;
17713576Sdlw 	int		index;
17813576Sdlw 	anything	*oper_addr;
17913576Sdlw 	anything	*reg_addr;
18013576Sdlw 
18113576Sdlw 	regnum = (**ipc & 0xf);
18213576Sdlw 	if (regnum == PC)
18313576Sdlw 		operand_code = (*(*ipc)++ & 0xff);
18413576Sdlw 	else
18513576Sdlw 		operand_code = (*(*ipc)++ & 0xf0);
18613576Sdlw 	if (regnum <= R6)
18713576Sdlw 		reg_addr = (anything *)&reg0_6->reg[regnum];
18813576Sdlw 	else if (regnum <= R11)
18913576Sdlw 		reg_addr = (anything *)&reg7_11->reg[regnum];
19013576Sdlw 	else if (regnum == AP)
19113576Sdlw 		reg_addr = (anything *)iap;
19213576Sdlw 	else if (regnum == FP)
19313576Sdlw 		reg_addr = (anything *)ifp;
19413576Sdlw 	else if (regnum == SP)
19513576Sdlw 		reg_addr = (anything *)&isp;	/* We saved this ourselves */
19613576Sdlw 	else if (regnum == PC)
19713576Sdlw 		reg_addr = (anything *)ipc;
19813576Sdlw 
19913576Sdlw 
20013576Sdlw 	switch (operand_code)
20113576Sdlw 	{
20213576Sdlw 		case IMMEDIATE:
20313576Sdlw 			oper_addr = (anything *)(*ipc);
20413576Sdlw 			*ipc += oper_size;
20513576Sdlw 			return(oper_addr);
20613576Sdlw 
20713576Sdlw 		case ABSOLUTE:
20813576Sdlw 			oper_addr = (anything *)(**ipc);
20913576Sdlw 			*ipc += sizeof (anything *);
21013576Sdlw 			return(oper_addr);
21113576Sdlw 
21213576Sdlw 		case LITERAL0:
21313576Sdlw 		case LITERAL1:
21413576Sdlw 		case LITERAL2:
21513576Sdlw 		case LITERAL3:
21613576Sdlw 			/* we don't care about the address of these */
21713576Sdlw 			return((anything *)0);
21813576Sdlw 
21913576Sdlw 		case INDEXED:
22013576Sdlw 			index = reg_addr->ua_long * oper_size;
22113576Sdlw 			oper_addr = (anything *)(get_operand(sizeof (long))->ua_long + index);
22213576Sdlw 			return(oper_addr);
22313576Sdlw 
22413576Sdlw 		case REGISTER:
22513576Sdlw 			return(reg_addr);
22613576Sdlw 
22713576Sdlw 		case REGDEFERED:
22813576Sdlw 			return(reg_addr->ua_anything);
22913576Sdlw 
23013576Sdlw 		case AUTODEC:
23113576Sdlw 			if (regnum == SP)
23213576Sdlw 			{
23313576Sdlw 				fprintf(stderr, "trp: can't fix -(SP) operand\n");
23413576Sdlw 				exit(1);
23513576Sdlw 			}
23613576Sdlw 			reg_addr->ua_long -= oper_size;
23713576Sdlw 			oper_addr = reg_addr->ua_anything;
23813576Sdlw 			return(oper_addr);
23913576Sdlw 
24013576Sdlw 		case AUTOINC:
24113576Sdlw 			if (regnum == SP)
24213576Sdlw 			{
24313576Sdlw 				fprintf(stderr, "trp: can't fix (SP)+ operand\n");
24413576Sdlw 				exit(1);
24513576Sdlw 			}
24613576Sdlw 			oper_addr = reg_addr->ua_anything;
24713576Sdlw 			reg_addr->ua_long += oper_size;
24813576Sdlw 			return(oper_addr);
24913576Sdlw 
25013576Sdlw 		case AUTOINCDEF:
25113576Sdlw 			if (regnum == SP)
25213576Sdlw 			{
25313576Sdlw 				fprintf(stderr, "trp: can't fix @(SP)+ operand\n");
25413576Sdlw 				exit(1);
25513576Sdlw 			}
25613576Sdlw 			oper_addr = (reg_addr->ua_anything)->ua_anything;
25713576Sdlw 			reg_addr->ua_long += sizeof (anything *);
25813576Sdlw 			return(oper_addr);
25913576Sdlw 
26013576Sdlw 		case BYTEDISP:
26113576Sdlw 		case BYTEREL:
26213626Sdlw 			index = ((anything *)(*ipc))->ua_byte;
26313626Sdlw 			*ipc += sizeof (char);	/* do it now in case reg==PC */
26413626Sdlw 			oper_addr = (anything *)(index + reg_addr->ua_long);
26513576Sdlw 			return(oper_addr);
26613576Sdlw 
26713576Sdlw 		case BYTEDISPDEF:
26813576Sdlw 		case BYTERELDEF:
26913626Sdlw 			index = ((anything *)(*ipc))->ua_byte;
27013626Sdlw 			*ipc += sizeof (char);	/* do it now in case reg==PC */
27113626Sdlw 			oper_addr = (anything *)(index + reg_addr->ua_long);
27213576Sdlw 			oper_addr = oper_addr->ua_anything;
27313576Sdlw 			return(oper_addr);
27413576Sdlw 
27513576Sdlw 		case WORDDISP:
27613576Sdlw 		case WORDREL:
27713626Sdlw 			index = ((anything *)(*ipc))->ua_word;
27813626Sdlw 			*ipc += sizeof (short);	/* do it now in case reg==PC */
27913626Sdlw 			oper_addr = (anything *)(index + reg_addr->ua_long);
28013576Sdlw 			return(oper_addr);
28113576Sdlw 
28213576Sdlw 		case WORDDISPDEF:
28313576Sdlw 		case WORDRELDEF:
28413626Sdlw 			index = ((anything *)(*ipc))->ua_word;
28513626Sdlw 			*ipc += sizeof (short);	/* do it now in case reg==PC */
28613626Sdlw 			oper_addr = (anything *)(index + reg_addr->ua_long);
28713576Sdlw 			oper_addr = oper_addr->ua_anything;
28813576Sdlw 			return(oper_addr);
28913576Sdlw 
29013576Sdlw 		case LONGDISP:
29113576Sdlw 		case LONGREL:
29213626Sdlw 			index = ((anything *)(*ipc))->ua_long;
29313626Sdlw 			*ipc += sizeof (long);	/* do it now in case reg==PC */
29413626Sdlw 			oper_addr = (anything *)(index + reg_addr->ua_long);
29513576Sdlw 			return(oper_addr);
29613576Sdlw 
29713576Sdlw 		case LONGDISPDEF:
29813576Sdlw 		case LONGRELDEF:
29913626Sdlw 			index = ((anything *)(*ipc))->ua_long;
30013626Sdlw 			*ipc += sizeof (long);	/* do it now in case reg==PC */
30113626Sdlw 			oper_addr = (anything *)(index + reg_addr->ua_long);
30213576Sdlw 			oper_addr = oper_addr->ua_anything;
30313576Sdlw 			return(oper_addr);
30413576Sdlw 
30513576Sdlw 		/* NOTREACHED */
30613576Sdlw 	}
30713576Sdlw }
30813576Sdlw 
30913576Sdlw /*
31013576Sdlw  * Trap & repair floating exceptions so that a program may proceed.
31113576Sdlw  * There is no notion of "correctness" here; just the ability to continue.
31213576Sdlw  *
31313576Sdlw  * The on_fpe() routine first checks the type code to see if the
31413576Sdlw  * exception is repairable. If so, it checks the opcode to see if
31513576Sdlw  * it is one that it knows. If this is true, it then simulates the
31613576Sdlw  * VAX cpu in retrieving operands in order to increment iPC correctly.
31713576Sdlw  * It notes where the result of the operation would have been stored
31813576Sdlw  * and substitutes a previously supplied value.
31913576Sdlw  */
32013576Sdlw 
32113576Sdlw #ifdef	OLD_BSD
32213576Sdlw on_fpe(signo, code, myaddr, pc, ps)
32313576Sdlw 	int signo, code, ps;
32413576Sdlw 	char *myaddr, *pc;
32513576Sdlw #else
32613576Sdlw on_fpe(signo, code, sc, grbg)
32713576Sdlw 	int signo, code;
32813576Sdlw 	struct sigcontext *sc;
32913576Sdlw #endif
33013576Sdlw {
33113576Sdlw 	/*
33213576Sdlw 	 * There must be at least 5 register variables here
33313576Sdlw 	 * so our entry mask will save R11-R7.
33413576Sdlw 	 */
33513576Sdlw 	register long	*stk;
33613576Sdlw 	register long	*sp;
33713576Sdlw 	register struct arglist	*ap;
33813576Sdlw 	register struct cframe	*fp;
33913576Sdlw 	register FILE	*ef;
34013576Sdlw 
34113576Sdlw 	ef = units[STDERR].ufd;		/* fortran error stream */
34213576Sdlw 
34313576Sdlw 	switch (code)
34413576Sdlw 	{
34513576Sdlw 		case FPE_INTOVF_TRAP:	/* integer overflow */
34613576Sdlw 		case FPE_INTDIV_TRAP:	/* integer divide by zero */
34713576Sdlw 		case FPE_FLTOVF_TRAP:	/* floating overflow */
34813576Sdlw 		case FPE_FLTDIV_TRAP:	/* floating/decimal divide by zero */
34913576Sdlw 		case FPE_FLTUND_TRAP:	/* floating underflow */
35013576Sdlw 		case FPE_DECOVF_TRAP:	/* decimal overflow */
35113576Sdlw 		case FPE_SUBRNG_TRAP:	/* subscript out of range */
35213576Sdlw 		default:
35313576Sdlw cant_fix:
35413576Sdlw 			if (sigfpe_dfl > (SIG_VAL)7)	/* user specified */
35513576Sdlw #ifdef	OLD_BSD
35613576Sdlw 				return((*sigfpe_dfl)(signo, code, myaddr, pc, ps));
35713576Sdlw #else
35813576Sdlw 				return((*sigfpe_dfl)(signo, code, sc, grbg));
35913576Sdlw #endif
36013576Sdlw 			else
36113576Sdlw #ifdef	OLD_BSD
36213576Sdlw 				sigdie(signo, code, myaddr, pc, ps);
36313576Sdlw #else
36413576Sdlw 				sigdie(signo, code, sc, grbg);
36513576Sdlw #endif
36613576Sdlw 			/* NOTREACHED */
36713576Sdlw 
36813576Sdlw 		case FPE_FLTOVF_FAULT:	/* floating overflow fault */
36913576Sdlw 		case FPE_FLTDIV_FAULT:	/* divide by zero floating fault */
37013576Sdlw 		case FPE_FLTUND_FAULT:	/* floating underflow fault */
37113576Sdlw 			if (++fpe_count <= max_messages) {
37213576Sdlw 				fprintf(ef, "trpfpe: %s",
37313576Sdlw 					act_fpe[code-1].mesg);
37413576Sdlw 				if (fpe_count == max_messages)
37513576Sdlw 					fprintf(ef, ": No more messages will be printed.\n");
37613576Sdlw 				else
37713576Sdlw 					fputc('\n', ef);
37813576Sdlw 			}
37913576Sdlw 			fpeflt_ = -1;
38013576Sdlw 			break;
38113576Sdlw 	}
38213576Sdlw 
38313576Sdlw 	ap = myap();			/* my arglist pointer */
38413576Sdlw 	fp = myfp();			/* my frame pointer */
38513576Sdlw 	ifp = &(fp->cf_fp)->cf_fp;	/* user's stored in next frame back */
38613576Sdlw 	iap = &(fp->cf_fp)->cf_ap;
38713576Sdlw 	/*
38813576Sdlw 	 * these are likely to be system dependent
38913576Sdlw 	 */
39013576Sdlw 	reg0_6 = (struct reg0_6 *)((char *)fp->cf_fp + sizeof (struct cframe));
39113576Sdlw 	reg7_11 = (struct reg7_11 *)((char *)fp->cf_fp - sizeof (struct reg7_11));
39213576Sdlw 
39313576Sdlw #ifdef	OLD_BSD
39413576Sdlw 	ipc = &pc;
39513576Sdlw 	isp = (char *)&ap->al_arg[ap->al_numarg + 2];	/* assumes 2 dummys */
39613576Sdlw 	ps &= ~(PSW_V|PSW_FU);
39713576Sdlw #else
39813576Sdlw 	ipc = (char **)&sc->sc_pc;
399*14635Sdlw 	isp = (char *)sc + sizeof (struct sigcontext);
40013576Sdlw 	sc->sc_ps &= ~(PSW_V|PSW_FU);
40113576Sdlw #endif
40213576Sdlw 
40313576Sdlw 
40413576Sdlw 	switch (*(*ipc)++)
40513576Sdlw 	{
40613576Sdlw 		case ADDD3:
40713576Sdlw 		case DIVD3:
40813576Sdlw 		case MULD3:
40913576Sdlw 		case SUBD3:
41013576Sdlw 			(void) get_operand(sizeof (double));
41113576Sdlw 			/* intentional fall-thru */
41213576Sdlw 
41313576Sdlw 		case ADDD2:
41413576Sdlw 		case DIVD2:
41513576Sdlw 		case MULD2:
41613576Sdlw 		case SUBD2:
41713576Sdlw 		case MNEGD:
41813576Sdlw 		case MOVD:
41913576Sdlw 			(void) get_operand(sizeof (double));
42013576Sdlw 			result_addr = get_operand(sizeof (double));
42113576Sdlw 			result_type = DOUBLE;
42213576Sdlw 			break;
42313576Sdlw 
42413576Sdlw 		case ADDF3:
42513576Sdlw 		case DIVF3:
42613576Sdlw 		case MULF3:
42713576Sdlw 		case SUBF3:
42813576Sdlw 			(void) get_operand(sizeof (float));
42913576Sdlw 			/* intentional fall-thru */
43013576Sdlw 
43113576Sdlw 		case ADDF2:
43213576Sdlw 		case DIVF2:
43313576Sdlw 		case MULF2:
43413576Sdlw 		case SUBF2:
43513576Sdlw 		case MNEGF:
43613576Sdlw 		case MOVF:
43713576Sdlw 			(void) get_operand(sizeof (float));
43813576Sdlw 			result_addr = get_operand(sizeof (float));
43913576Sdlw 			result_type = FLOAT;
44013576Sdlw 			break;
44113576Sdlw 
44213576Sdlw 		case CVTDF:
44313576Sdlw 			(void) get_operand(sizeof (double));
44413576Sdlw 			result_addr = get_operand(sizeof (float));
44513576Sdlw 			result_type = FLOAT;
44613576Sdlw 			break;
44713576Sdlw 
44813576Sdlw 		case CVTFD:
44913576Sdlw 			(void) get_operand(sizeof (float));
45013576Sdlw 			result_addr = get_operand(sizeof (double));
45113576Sdlw 			result_type = DOUBLE;
45213576Sdlw 			break;
45313576Sdlw 
45413576Sdlw 		case EMODF:
45513576Sdlw 		case EMODD:
45613576Sdlw 			fprintf(ef, "trpfpe: can't fix emod yet\n");
45713576Sdlw 			goto cant_fix;
45813576Sdlw 
45913576Sdlw 		case POLYF:
46013576Sdlw 		case POLYD:
46113576Sdlw 			fprintf(ef, "trpfpe: can't fix poly yet\n");
46213576Sdlw 			goto cant_fix;
46313576Sdlw 
46413576Sdlw 		case ACBD:
46513576Sdlw 		case ACBF:
46613576Sdlw 		case CMPD:
46713576Sdlw 		case CMPF:
46813576Sdlw 		case TSTD:
46913576Sdlw 		case TSTF:
47013576Sdlw 		case CVTDB:
47113576Sdlw 		case CVTDL:
47213576Sdlw 		case CVTDW:
47313576Sdlw 		case CVTFB:
47413576Sdlw 		case CVTFL:
47513576Sdlw 		case CVTFW:
47613576Sdlw 		case CVTRDL:
47713576Sdlw 		case CVTRFL:
47813576Sdlw 			/* These can generate only reserved operand faults */
47913576Sdlw 			/* They are shown here for completeness */
48013576Sdlw 
48113576Sdlw 		default:
48213576Sdlw 			fprintf(stderr, "trp: opcode 0x%02x unknown\n",
48313576Sdlw 				*(--(*ipc)) & 0xff);
48413576Sdlw 			goto cant_fix;
48513576Sdlw 			/* NOTREACHED */
48613576Sdlw 	}
48713576Sdlw 
48813576Sdlw 	if (result_type == FLOAT)
48913576Sdlw 		result_addr->ua_float = retval.rv_float;
49013576Sdlw 	else
49113576Sdlw 	{
49213576Sdlw 		if (result_addr == (anything *)&iR6)
49313576Sdlw 		{	/*
49413576Sdlw 			 * special case - the R6/R7 pair is stored apart
49513576Sdlw 			 */
49613576Sdlw 			result_addr->ua_long = retval.rv_long[0];
49713576Sdlw 			((anything *)&iR7)->ua_long = retval.rv_long[1];
49813576Sdlw 		}
49913576Sdlw 		else
50013576Sdlw 			result_addr->ua_double = retval.rv_double;
50113576Sdlw 	}
50213576Sdlw 	signal(SIGFPE, on_fpe);
50313576Sdlw }
50413576Sdlw #endif	vax
50513576Sdlw 
50613576Sdlw trpfpe_ (count, rval)
50713576Sdlw 	long	*count;	/* how many to announce */
50813576Sdlw 	double	*rval;	/* dummy return value */
50913576Sdlw {
51013576Sdlw #if	vax
51113576Sdlw 	max_messages = *count;
51213576Sdlw 	retval.rv_double = *rval;
51313576Sdlw 	sigfpe_dfl = signal(SIGFPE, on_fpe);
51413576Sdlw 	fpe_count = 0;
51513576Sdlw #endif
51613576Sdlw }
51713576Sdlw 
51813576Sdlw long
51913576Sdlw fpecnt_ ()
52013576Sdlw {
52113576Sdlw #if	vax
52213576Sdlw 	return (fpe_count);
52313576Sdlw #else
52413576Sdlw 	return (0L);
52513576Sdlw #endif
52613576Sdlw }
52713576Sdlw 
528