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