🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

1 total messages Started by Mike Rendell Sat, 26 Sep 1992 16:29
Double arg passing bugs, gcc 2.2.2 for hppa1.1 (+fixes)
#1219
Author: Mike Rendell
Date: Sat, 26 Sep 1992 16:29
240 lines
8157 bytes
Gcc 2.2.2 for hppa1.1 has two problems with passing double arguments:
one for varargs functions and one for functions whose fourth argument
is a double.

The first problem occurs when a double argument is passed as one of the
first three arguments to a varargs function: the value returned by
va_arg() is incorrect.  The following program demonstrates the problem:

	#include	<stdio.h>
	#include	<stdarg.h>

	void
	foobar(char *str, ...)
	{
		va_list	args;

		va_start(args, str);
		printf("%s %g\n", str, va_arg(args, double));
		va_end(args);
	}

	void
	main(void)
	{
		foobar("hi", 5.0);
	}

The problem is that the function hppa_builtin_saveregs() in config/pa.c
flushes float registers %fr3,%fr4,%fr5,%fr6 and double registers %fr4,%fr6
instead of float registers %fr4,%fr5,%fr6,%fr7 and double registers
%fr5,%fr7.  The following context diff for config/pa.c fixes the problem.

*** pa.c.orig	Fri Sep 25 13:24:07 1992
--- pa.c	Fri Sep 25 13:25:56 1992
***************
*** 2374,2392 ****
  					     0, 0, OPTAB_LIB_WIDEN)));
    /* Store fp registers. */
    emit_move_insn (gen_rtx (MEM, SFmode, float_addr),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 60 : 39));
    emit_move_insn (gen_rtx (MEM, SFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 4))),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 58 : 38));
    emit_move_insn (gen_rtx (MEM, SFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 8))),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 56 : 37));
    emit_move_insn (gen_rtx (MEM, SFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 12))),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 54 : 36));
    /* 
     * Allocate space for the double args, and store it in the 
     * __va_double member.
--- 2374,2392 ----
  					     0, 0, OPTAB_LIB_WIDEN)));
    /* Store fp registers. */
    emit_move_insn (gen_rtx (MEM, SFmode, float_addr),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 62 : 39));
    emit_move_insn (gen_rtx (MEM, SFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 4))),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 60 : 38));
    emit_move_insn (gen_rtx (MEM, SFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 8))),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 58 : 37));
    emit_move_insn (gen_rtx (MEM, SFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 12))),
! 		  gen_rtx (REG, SFmode, TARGET_SNAKE ? 56 : 36));
    /* 
     * Allocate space for the double args, and store it in the 
     * __va_double member.
***************
*** 2409,2418 ****
    /* Store fp registers as doubles. */
  
    emit_move_insn (gen_rtx (MEM, DFmode, float_addr),
! 		  (gen_rtx (REG, DFmode, TARGET_SNAKE ? 60 : 39)));
    emit_move_insn (gen_rtx (MEM, DFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 8))),
! 		  gen_rtx (REG, DFmode, TARGET_SNAKE ? 56 : 37));
    return copy_to_reg (XEXP (block, 0));
  }
--- 2409,2418 ----
    /* Store fp registers as doubles. */
  
    emit_move_insn (gen_rtx (MEM, DFmode, float_addr),
! 		  (gen_rtx (REG, DFmode, TARGET_SNAKE ? 62 : 39)));
    emit_move_insn (gen_rtx (MEM, DFmode, gen_rtx (PLUS, Pmode, float_addr,
  						 gen_rtx (CONST_INT,
  							  Pmode, 8))),
! 		  gen_rtx (REG, DFmode, TARGET_SNAKE ? 58 : 37));
    return copy_to_reg (XEXP (block, 0));
  }


The second problem occurs when a function's fourth argument is a double
and the preceeding three arguments are pointers/ints/shorts/chars.
The .EXPORT directive generated for such a function says the fourth
argument is in a register (ARG3=FR,ARG4=FU) when in fact it is not.
The following program demonstrates the problem:

	int
	blah(int a, int b, int c, double d)
	{
		return (int) d;
	}

	void
	main(void)
	{
		blah(1, 2, 3, 4.0);
	}

The result from gcc is:

% gcc -v -O t.c
Reading specs from /usr/local/lib/gcc-lib/hppa1.1-hp720-hpux/2.2.2/specs
gcc version 2.2.2
 /usr/local/lib/gcc-lib/hppa1.1-hp720-hpux/2.2.2/cpp -lang-c -v -undef -D__GNUC__=2 -Dhppa -Dhp9000s800 -Dhp9000s700 -Dhp9k8 -DPWB -Dhpux -Dunix -D_HPUX_SOURCE -D__hppa__ -D__hp9000s800__ -D__hp9000s700__ -D__hp9k8__ -D__PWB__ -D__hpux__ -D__unix__ -D___HPUX_SOURCE__ -D__hppa -D__hp9000s800 -D__hp9000s700 -D__hp9k8 -D__PWB -D__hpux -D__unix -D___HPUX_SOURCE -D__OPTIMIZE__ t.c /usr/tmp/cca10054.i
GNU CPP version 2.2.2 (hp9000s800)
 /usr/local/lib/gcc-lib/hppa1.1-hp720-hpux/2.2.2/cc1 /usr/tmp/cca10054.i -quiet -dumpbase t.c -O -version -o /usr/tmp/cca10054.s
GNU C version 2.2.2 (hp9000s800) compiled by GNU C version 2.2.2.
 /usr/local/lib/gcc-lib/hppa1.1-hp720-hpux/2.2.2/as -o t.o /usr/tmp/cca10054.s
/usr/tmp/cca10054.s:14:Illegal argument description: 255
gcc: t.o: No such file or directory
% gcc -O -S t.c
% cat t.s
	.SPACE $PRIVATE$
	.SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31
	.SPACE $TEXT$
	.SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44
	.SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
	.IMPORT $global$,DATA
	.IMPORT $$dyncall,MILLICODE
; gcc_compiled.:
	.SPACE $TEXT$
	.SUBSPA $CODE$

	.align 4
	.EXPORT blah
	.EXPORT blah,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=FR,ARGW4=FU,RTNVAL=GR
blah
	.PROC
	.CALLINFO FRAME=64,NO_CALLS
	.ENTRY
	copy 4,1
	copy 30,4
	stwm 1,64(0,30)
	ldo -56(%r4),%r19
	fldds 0(0,%r19),%fr4
	fcnvfxt,dbl,sgl %fr4,%fr5
	fstws %fr5,-16(30)
	ldw -16(30),%r28
	ldo 8(4),30
	bv 0(2)
	ldwm -8(30),4
	.EXIT
	.PROCEND
	.IMPORT __main,CODE
	.align 8
LC$0000
	; .double 4.00000000000000000000e+00
	.word 1074790400 ; = 0x40100000
	.word 0 ; = 0x0
	.align 4
	.EXPORT main
	.EXPORT main,PRIV_LEV=3,RTNVAL=GR
main
	.PROC
	.CALLINFO FRAME=128,CALLS,SAVE_RP
	.ENTRY
	stw 2,-20(0,30)
	copy 4,1
	copy 30,4
	stwm 1,128(0,30)
	.CALL 
	bl __main,2
	nop
	ldo -56(%r30),%r20
	ldil L'LC$0000,%r19
	ldo R'LC$0000(%r19),%r19
	ldw 0(0,%r19),%r22
	ldw 4(0,%r19),%r23
	stw %r22,-16(0,30)
	stw %r23,-12(0,30)
	fldds -16(0,30),%fr4
	fstds %fr4,0(0,%r20)
	ldo 1(0),%r26
	ldo 2(0),%r25
	ldo 3(0),%r24
	.CALL ARGW0=GR,ARGW1=GR,ARGW2=GR
	bl blah,2
	nop
	ldo 8(4),30
	ldw -28(0,30),2
	bv 0(2)
	ldwm -8(30),4
	.EXIT
	.PROCEND

Note the .EXPORT line for blah says the fourth argument is in a register while
the code for blah takes the argument from the stack.  The problem is in the
ASM_DECLARE_FUNCTION_NAME macro in config/pa.h which does an alignment check
for a double in the second argument, but not the fourth.  If a double is in
the fourth argument, nothing should be printed.  The following context diff
for config/pa.h fixes the problem (note that i must be incremented to 4
when i == 3 since it is used later in the macro).

*** pa.h.orig	Sat Sep 26 10:50:26 1992
--- pa.h	Sat Sep 26 10:53:09 1992
***************
*** 783,789 ****
  		   fprintf (FILE, ",ARGW%d=FR", i++);			\
  		 else if (TYPE_MODE (DECL_ARG_TYPE (parm)) == DFmode)	\
  		   {							\
! 		      if (i == 1) i++;				        \
  		      ASM_DOUBLE_ARG_DESCRIPTORS (FILE, i++, i++);	\
  		   }							\
  		 else							\
--- 783,793 ----
  		   fprintf (FILE, ",ARGW%d=FR", i++);			\
  		 else if (TYPE_MODE (DECL_ARG_TYPE (parm)) == DFmode)	\
  		   {							\
! 		      if (i & 1)					\
! 			{						\
! 			  i++;						\
! 			  if (i == 4) break;				\
! 			}						\
  		      ASM_DOUBLE_ARG_DESCRIPTORS (FILE, i++, i++);	\
  		   }							\
  		 else							\


--
Michael Rendell - Dept. of Comp. Sci., Memorial University of Newfoundland
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads