[gnu.gcc.bug] -fpcc-struct-return bug in 1.36 on Pyramid, others?

jonathan@comp.vuw.ac.nz (11/22/89)

Version/Machine:
	gcc 1.36  on Pyramid 90x, with 1 RMS patch to combine.c.

Symptom::
	programs compiled with gcc -fpcc-struct-return dump core or
	produce incorrect results when functions return structures.
	(reputedly on sparcs too; I don't have one to check.)

Repeat-by::
	Unshar the appended programs and do ``make runtests''.
	Note that the gcc-compiled called function behaves
	improperly when called from either pcc- or gcc-compiled code.
	
Fix::
	Reading the assembler output of gcc reveals that with
	-fpcc-struct-return, the called function return the address of
	a static location containing the return structure in the
	wrong register (the function-value input register, instead of
	the function-value output register).
	The following changes fixes this simply.  Perhaps defining a
	function hard_function_outgoing_register() would be
	stylistically preferable.

*** /usr/src/gnu/gcc-1.36/stmt.c	Thu Sep 21 16:29:53 1989
--- ./stmt.c	Wed Nov 22 13:39:26 1989
***************
*** 4838,4846 ****
--- 4838,4853 ----
      {
        rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
        tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+ 
+ #ifdef FUNCTION_OUTGOING_VALUE
        rtx outgoing
+ 	= FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
+ 				   current_function_decl);
+ #else
+       rtx outgoing
  	= hard_function_value (build_pointer_type (type),
  			       current_function_decl);
+ #endif
  
        REG_FUNCTION_VALUE_P (outgoing) = 1;
        emit_move_insn (outgoing, value_address);

	

Test cases::


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  struct-returning-fn.c struct-returning-call.c
#   struct-test.h Makefile
# Wrapped by jonathan@embassy.comp.vuw.ac.nz on Wed Nov 22 14:18:10 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'struct-returning-fn.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'struct-returning-fn.c'\"
else
echo shar: Extracting \"'struct-returning-fn.c'\" \(1071 characters\)
sed "s/^X//" >'struct-returning-fn.c' <<'END_OF_FILE'
X/*  Called routine for testing  return of structure values from
X    functions with gcc -fpcc-struct-return.  This function
X    should be compiled with both cc and gcc -fpcc-struct-return,
X    linked with the calling function, 
X    compiled with both cc and gcc -fpcc-struct-return,
X    and the results of running these four programs compared.
X    If they are not identical, -fpcc-struct-return is broken.
X  */
X
X
X#include "struct-test.h"
X
X/* This function returns a structure that will fit in a register on
X   most machines */
X
Xextern fits_in_reg other_foo ();
X
Xfits_in_reg other_foo ()
X{
X  fits_in_reg result;
X  result.i1 = 0xaa55;
X  kill_optimiser (&result);
X  return (result);
X}
X
Xbig_struct fn_returning_big_struct ()
X{
X  big_struct answer;
X  answer.a1=0xbf9a;
X  answer.a2=0xabcd;
X  answer.a3=0x33333333;
X  answer.a4=9999000;
X  kill_optimiser(&answer);
X  return(answer);
X}
X
X/* Both call a function returning a structure and return a structure.*/
Xfits_in_reg
Xfoo (a1, a2, a3, a4, a5)
X    int a1, a5;
X{
X  fits_in_reg result;
X  result = other_foo();
X  return (result);
X}
X
END_OF_FILE
if test 1071 -ne `wc -c <'struct-returning-fn.c'`; then
    echo shar: \"'struct-returning-fn.c'\" unpacked with wrong size!
fi
# end of 'struct-returning-fn.c'
fi
if test -f 'struct-returning-call.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'struct-returning-call.c'\"
else
echo shar: Extracting \"'struct-returning-call.c'\" \(990 characters\)
sed "s/^X//" >'struct-returning-call.c' <<'END_OF_FILE'
X/* do-struct-returning-call:
X   call a function that returns a structure. */
X
X#include "struct-test.h"
X
Xextern fits_in_reg other_foo();
Xint kill_optimiser();
X
Xmain (argc, argv)
X    int argc;
X    char *argv [];
X{
X  int one, two, three, four;
X  big_struct local_test;
X
X#if 0
X  /* An old test that superficialy checks whether structure members
X     overlay one another. */
X  one = a1;
X  two = a2.i1;
X  three = a3.a3;
X  four = a4.i1;
X  
X  printf("1= %d  12 = %d 13 = %d 14 = %d\n", one, two, three, four);
X
X  kill_optimiser(&one);
X  kill_optimiser(&two);
X  kill_optimiser(&three);
X  kill_optimiser(&four);
X
X
Xexit:
X  {
X    printf ("test FAILED\n");
X    exit(1);
X  }
X#endif
X
X  fits_in_reg returned_from_fn;
X  returned_from_fn = other_foo();
X  if (returned_from_fn.i1 == 0xaa55) {
X    exit(0);
X  } else {
X    printf ("pcc-struct-return test FAILED\n");
X    exit(1);
X  }
X}
X
X
X/* Make the optimiser not know anything about any quanity in memory. */
Xint
Xkill_optimiser(x)
X    char *x;
X{
X  return 0;
X}
END_OF_FILE
if test 990 -ne `wc -c <'struct-returning-call.c'`; then
    echo shar: \"'struct-returning-call.c'\" unpacked with wrong size!
fi
# end of 'struct-returning-call.c'
fi
if test -f 'struct-test.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'struct-test.h'\"
else
echo shar: Extracting \"'struct-test.h'\" \(429 characters\)
sed "s/^X//" >'struct-test.h' <<'END_OF_FILE'
X/* struct-test.h : test passing and returning of structures to/from
X   functions in gcc and standard pcc. */
X
X
X/* On machines where structs can be passed to functions (or returned
X   from functions) in registers, this struct should be put in a reg.   */ 
X
Xtypedef struct fits_in_reg {
X  int i1;
X} fits_in_reg;
X
X
X/* Another structure that shouldn't fit in regs */
X
Xtypedef struct big_struct {
X  int a1, a2, a3, a4;
X} big_struct;
X
END_OF_FILE
if test 429 -ne `wc -c <'struct-test.h'`; then
    echo shar: \"'struct-test.h'\" unpacked with wrong size!
fi
# end of 'struct-test.h'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1588 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Makefile to test -fpcc-struct-return
X#
X
XGCC_DEBUG_FLAGS = -g -O
XGCC	= gcc -c $(GCC_DEBUG_FLAGS) $(XGCCFLAGS) -fpcc-struct-return
XLD	= gcc
XSRC	= struct-returning-fn.c struct-returning-call.c struct-test.h
X# Uncomment the next line on Pyrs
XCC_DEBUG_FLAGS = -gx
X# Uncomment the next line on everything else
X#CC_DEBUG_FLAGS = -g
XCC	= cc  -c $(CC_DEBUG_FLAGS) $(XCCFLAGS)
X
XTESTPROGS = test-pcc-calling-pcc test-gcc-calling-pcc \
X		test-pcc-calling-gcc test-gcc-calling-gcc
X
Xtest-progs: $(TESTPROGS)
X
Xtest-pcc-calling-pcc: pcc-caller.o pcc-callee.o
X	$(LD) -o test-pcc-calling-pcc pcc-caller.o pcc-callee.o
X
Xtest-gcc-calling-pcc:  gcc-caller.o pcc-callee.o
X	$(LD) -o test-gcc-calling-pcc gcc-caller.o pcc-callee.o
X
Xtest-pcc-calling-gcc:   pcc-caller.o gcc-callee.o
X	$(LD) -o test-pcc-calling-gcc pcc-caller.o gcc-callee.o
X
Xtest-gcc-calling-gcc:   gcc-caller.o gcc-callee.o
X	$(LD) -o test-gcc-calling-gcc gcc-caller.o gcc-callee.o
X
X
Xpcc-caller.o:  struct-returning-call.c
X	$(CC) $(CFLAGS) struct-returning-call.c
X	mv struct-returning-call.o pcc-caller.o
X
Xpcc-callee.o: struct-returning-fn.c
X	$(CC) $(CFLAGS) struct-returning-fn.c
X	mv struct-returning-fn.o pcc-callee.o
X
X
Xgcc-caller.o: struct-returning-call.c
X	$(GCC) $(CFLAGS) -o gcc-caller.o struct-returning-call.c
X
Xgcc-callee.o: struct-returning-fn.c
X	$(GCC) $(CFLAGS) -o gcc-callee.o struct-returning-fn.c
X
X
Xruntests: test-progs
X	for i in $(TESTPROGS); do \
X		echo $$i ; $$i; \
X	 done
X
Xclean: cleanprogs
X	rm -f gcc-callee.o gcc-caller.o pcc-callee.o pcc-caller.o
X
Xcleanprogs:
X	rm -f $(TESTPROGS)
X
Xdist:
X	shar -o dist.shar $(SRC) Makefile
END_OF_FILE
if test 1588 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
echo shar: End of shell archive.
exit 0