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