Subject: [zack@codesourcery.com: PowerPC SVR4 ABI compliance fix]
To: None <port-powerpc@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: port-powerpc
Date: 11/21/2001 15:35:57
So you're all aware of it.

----- Forwarded message from Zack Weinberg <zack@codesourcery.com> -----

To: gcc-patches@gcc.gnu.org
Date: Wed, 21 Nov 2001 14:34:06 -0800
From: Zack Weinberg <zack@codesourcery.com>
Subject: PowerPC SVR4 ABI compliance fix

The PowerPC SVR4 ABI specifies that structures smaller than 8 bytes
are to be returned in general registers r3 and r4.  GCC ignores this
and returns all structures in memory (this is the behavior specified
by the AIX ABI, and apparently a draft of the SVR4 ABI matched it).
The appended patch corrects GCC's behavior.

THIS PATCH BREAKS BINARY COMPATIBILITY.  I have included a per-target
override macro to restore the old behavior, and command line switches
to override that.  I have set the override for Linux, NetBSD, and
FreeBSD.  All the other configurations based on ABI_V4 will break:
these are

powerpc*-*-sysv*
powerpc*-*-chorusos*
powerpc*-*-eabi*
powerpc*-*-elf*
powerpc*-*-rtems*
powerpc*-*-vxworks*

As they are all embedded or rarely used, I suspect there will be no
serious problems.  (This change was explicitly requested by the
maintainers of VxWorks, for compatibility with other compilers used
for that target.)

Maintainers of PowerPC Linux, NetBSD, and FreeBSD should consider
whether and when they can cope with an ABI change, and remove the
override from their header files when appropriate.

Tested with an ix86-linux -> powerpc-eabisim cross compiler and
simulated testsuite run.

I also zapped two uses of '%$' which I missed in the previous sweep.
Why someone used %c instead of %% to get a percent sign in the result
of sprintf, I'd like to know ... actually, no I wouldn't. :-)

zw

	* config/rs6000/rs6000.h (MASK_AIX_STRUCT_RET,
	MASK_AIX_STRUCT_RET_SET, TARGET_AIX_STRUCT_RET): New
	target_flags macros.
	(TARGET_SWITCHES): Add -m(no-)aix-struct-return and
	-m(no-)svr4-struct-return.
	(RETURN_IN_MEMORY): If !TARGET_AIX_STRUCT_RET, return small
	aggregates in registers.
	(DRAFT_V4_STRUCT_RET): Default to 0.
	* config/rs6000/freebsd.h, config/rs6000/linux.h,
	config/rs6000/netbsd.h: Redefine DRAFT_V4_STRUCT_RET to 1.
	* config/rs6000/rs6000.c (rs6000_override_options): Set
	MASK_AIX_STRUCT_RET from DEFAULT_ABI and DRAFT_V4_STRUCT_RET,
	if not set on the command line.
	* doc/invoke.texi: Document -m(no-)aix-struct-return and
	-m(no-)svr4-struct-return.

	* config/rs6000/rs6000.c (output_cbranch): Use plain $, not
	%$, in output template.
	* config/rs6000/rs6000.md (anonymous insn): Likewise.


===================================================================
Index: config/rs6000/freebsd.h
--- config/rs6000/freebsd.h	2001/11/20 19:43:27	1.1
+++ config/rs6000/freebsd.h	2001/11/21 22:20:42
@@ -38,6 +38,11 @@ the Free Software Foundation, 675 Mass A
 #undef	LINK_OS_DEFAULT_SPEC
 #define	LINK_OS_DEFAULT_SPEC "%(link_os_freebsd)"
 
+/* For backward compatibility, we must continue to use the AIX
+   structure return convention.  */
+#undef DRAFT_V4_STRUCT_RET
+#define DRAFT_V4_STRUCT_RET 1
+
 
 /************************[  Target stuff  ]***********************************/
 
===================================================================
Index: config/rs6000/linux.h
--- config/rs6000/linux.h	2001/11/15 05:21:06	1.30
+++ config/rs6000/linux.h	2001/11/21 22:20:42
@@ -69,6 +69,11 @@ Boston, MA 02111-1307, USA.  */
 #undef ASM_APP_OFF
 #define ASM_APP_OFF "#NO_APP\n"
 
+/* For backward compatibility, we must continue to use the AIX
+   structure return convention.  */
+#undef DRAFT_V4_STRUCT_RET
+#define DRAFT_V4_STRUCT_RET 1
+
 /* Do code reading to identify a signal frame, and set the frame
    state data appropriately.  See unwind-dw2.c for the structs.  */
 
===================================================================
Index: config/rs6000/netbsd.h
--- config/rs6000/netbsd.h	2001/11/15 05:21:06	1.2
+++ config/rs6000/netbsd.h	2001/11/21 22:20:42
@@ -59,3 +59,8 @@ Boston, MA 02111-1307, USA.  */
 
 #undef TARGET_VERSION
 #define TARGET_VERSION fprintf (stderr, " (PowerPC NetBSD/ELF)");
+
+/* For backward compatibility, we must continue to use the AIX
+   structure return convention.  */
+#undef DRAFT_V4_STRUCT_RET
+#define DRAFT_V4_STRUCT_RET 1
===================================================================
Index: config/rs6000/rs6000.c
--- config/rs6000/rs6000.c	2001/11/21 02:57:14	1.240
+++ config/rs6000/rs6000.c	2001/11/21 22:20:43
@@ -489,6 +489,17 @@ rs6000_override_options (default_cpu)
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
+     If -maix-struct-return or -msvr4-struct-return was explicitly
+     used, don't override with the ABI default.  */
+  if (!(target_flags & MASK_AIX_STRUCT_RET_SET))
+    {
+      if (DEFAULT_ABI == ABI_V4 && !DRAFT_V4_STRUCT_RET)
+	target_flags = (target_flags & ~MASK_AIX_STRUCT_RET);
+      else
+	target_flags |= MASK_AIX_STRUCT_RET;
+    }
+
   /* Register global variables with the garbage collector.  */
   rs6000_add_gc_roots ();
 
@@ -5681,7 +5692,7 @@ output_cbranch (op, label, reversed, ins
       /* If the branch distance was too far, we may have to use an
 	 unconditional branch to go the distance.  */
       if (need_longbranch)
-	s += sprintf (s, ",%c$+8\n\tb %s", '%', label);
+	s += sprintf (s, ",$+8\n\tb %s", label);
       else
 	s += sprintf (s, ",%s", label);
     }
===================================================================
Index: config/rs6000/rs6000.h
--- config/rs6000/rs6000.h	2001/11/21 02:57:15	1.142
+++ config/rs6000/rs6000.h	2001/11/21 22:20:44
@@ -217,6 +217,10 @@ extern int target_flags;
 /* Use 128-bit long double.  */
 #define MASK_LONG_DOUBLE_128	0x00200000
 
+/* Return small structures in memory (as the AIX ABI requires).  */
+#define MASK_AIX_STRUCT_RET	0x00400000
+#define MASK_AIX_STRUCT_RET_SET	0x00800000
+
 #define TARGET_POWER		(target_flags & MASK_POWER)
 #define TARGET_POWER2		(target_flags & MASK_POWER2)
 #define TARGET_POWERPC		(target_flags & MASK_POWERPC)
@@ -238,6 +242,7 @@ extern int target_flags;
 #define TARGET_ALTIVEC		(target_flags & MASK_ALTIVEC)
 #define TARGET_ALTIVEC_ABI	(target_flags & MASK_ALTIVEC_ABI)
 #define TARGET_LONG_DOUBLE_128	(target_flags & MASK_LONG_DOUBLE_128)
+#define TARGET_AIX_STRUCT_RET	(target_flags & MASK_AIX_STRUCT_RET)
 
 #define TARGET_32BIT		(! TARGET_64BIT)
 #define TARGET_HARD_FLOAT	(! TARGET_SOFT_FLOAT)
@@ -354,6 +359,18 @@ extern int target_flags;
 			""},						\
   {"no-sched-epilog",   -MASK_SCHED_PROLOG,                             \
 			""},						\
+  {"aix-struct-return",	MASK_AIX_STRUCT_RET | MASK_AIX_STRUCT_RET_SET,	\
+			N_("Return all structures in memory (AIX default)")},\
+  {"svr4-struct-return", - MASK_AIX_STRUCT_RET,\
+			N_("Return small structures in registers (SVR4 default)")},\
+  {"svr4-struct-return",MASK_AIX_STRUCT_RET_SET,\
+			""},\
+  {"no-aix-struct-return", - MASK_AIX_STRUCT_RET,\
+			""},\
+  {"no-aix-struct-return", MASK_AIX_STRUCT_RET_SET,\
+			""},\
+  {"no-svr4-struct-return", MASK_AIX_STRUCT_RET | MASK_AIX_STRUCT_RET_SET,\
+			""},\
   SUBTARGET_SWITCHES							\
   {"",			TARGET_DEFAULT | MASK_SCHED_PROLOG,		\
 			""}}
@@ -1432,15 +1449,23 @@ typedef struct rs6000_stack {
 		     : GET_MODE_CLASS (MODE) == MODE_FLOAT		\
 		     && TARGET_HARD_FLOAT				\
 		     ? FP_ARG_RETURN : GP_ARG_RETURN)
-
-/* The definition of this macro implies that there are cases where
-   a scalar value cannot be returned in registers.
 
-   For the RS/6000, any structure or union type is returned in memory.
-   (FIXME: Except for V.4, where those <= 8 bytes are returned in
-   registers.  Can't change this without breaking compatibility.)  */
+/* The AIX ABI for the RS/6000 specifies that all structures are
+   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
+   specifies that structures <= 8 bytes are returned in r3/r4, but a
+   draft put them in memory, and GCC used to implement the draft
+   instead of the final standard.  Therefore, TARGET_AIX_STRUCT_RET
+   controls this instead of DEFAULT_ABI; V.4 targets needing backward
+   compatibility can change DRAFT_V4_STRUCT_RET to override the
+   default, and -m switches get the final word.  See
+   rs6000_override_options for more details.  */
+   
+#define RETURN_IN_MEMORY(TYPE) \
+  (AGGREGATE_TYPE_P (TYPE) && \
+   (TARGET_AIX_STRUCT_RET || int_size_in_bytes (TYPE) > 8))
 
-#define RETURN_IN_MEMORY(TYPE) AGGREGATE_TYPE_P (TYPE)
+/* DRAFT_V4_STRUCT_RET defaults off.  */
+#define DRAFT_V4_STRUCT_RET 0
 
 /* Let RETURN_IN_MEMORY control what happens.  */
 #define DEFAULT_PCC_STRUCT_RETURN 0
===================================================================
Index: config/rs6000/rs6000.md
--- config/rs6000/rs6000.md	2001/11/21 02:57:15	1.137
+++ config/rs6000/rs6000.md	2001/11/21 22:20:46
@@ -10241,7 +10241,7 @@
 	(compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "f")
 		      (match_operand:TF 2 "gpc_reg_operand" "f")))]
   "DEFAULT_ABI == ABI_AIX && TARGET_HARD_FLOAT && TARGET_LONG_DOUBLE_128"
-  "fcmpu %0,%1,%2\;bne %0,%$+4\;fcmpu %0,%L1,%L2"
+  "fcmpu %0,%1,%2\;bne %0,$+4\;fcmpu %0,%L1,%L2"
   [(set_attr "type" "fpcompare")
    (set_attr "length" "12")])
 
===================================================================
Index: doc/invoke.texi
--- doc/invoke.texi	2001/11/18 17:16:22	1.78
+++ doc/invoke.texi	2001/11/21 22:20:49
@@ -441,6 +441,7 @@ in the following sections.
 -mno-relocatable  -mrelocatable-lib  -mno-relocatable-lib @gol
 -mtoc  -mno-toc -mlittle  -mlittle-endian  -mbig  -mbig-endian @gol
 -mcall-aix -mcall-sysv -mcall-netbsd @gol
+-maix-struct-return -msvr4-struct-return
 -mabi=altivec @gol
 -mprototype  -mno-prototype @gol
 -msim  -mmvme  -mads  -myellowknife  -memb -msdata @gol
@@ -6946,6 +6947,15 @@ Linux-based GNU system.
 @opindex mcall-netbsd
 On System V.4 and embedded PowerPC systems compile code for the
 NetBSD operating system.
+
+@item -maix-struct-return
+@opindex maix-struct-return
+Return all structures in memory (as specified by the AIX ABI).
+
+@item -msvr4-struct-return
+@opindex msvr4-struct-return
+Return structures smaller than 8 bytes in registers (as specified by the
+SVR4 ABI).
 
 @item -mabi=altivec
 @opindex mabi=altivec

----- End forwarded message -----

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>