This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PPC SVR4 ABI fix - take two
- From: Zack Weinberg <zack at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 2 Dec 2001 16:01:28 -0800
- Subject: PPC SVR4 ABI fix - take two
This is a revised version of the patch to correct GCC's implementation
of structure return under the PPC SVR4 ABI. I moved two entries out
of target_flags, leaving room for the bit I need, and one more for
future expansion (which I have plans for, take note).
Tested by i386-linux -> powerpc-eabisim cross compiler and simulated
testsuite run, C only. The tree had my patch to fold
(build,cross)-make into configure.in applied to it. A list of
testsuite failures is appended to this message.
There's also a warning fix - the init_builtins backend hook no longer
takes any arguments. Finally, I took '$' and '*' out of
PRINT_OPERAND_PUNCT_VALID_P, they are no longer used.
zw
* config/rs6000/rs6000.h (MASK_ALTIVEC_ABI,
MASK_LONG_DOUBLE_128): Delete.
(MASK_AIX_STRUCT_RET, MASK_AIX_STRUCT_RET_SET,
TARGET_AIX_STRUCT_RET): New flags.
(TARGET_SWITCHES): Remove entries for -mlong-double-128 and
-mlong-double-64. Add entries for -m(no-)aix-struct-return
and -m(no-)svr4-struct-return.
(TARGET_OPTIONS): Add entry for -mlong-double-.
(rs6000_long_double_size_string, rs6000_long_double_type_size,
rs6000_altivec_abi): Declare.
(TARGET_LONG_DOUBLE_128, TARGET_ALTIVEC_ABI,
LONG_DOUBLE_TYPE_SIZE): Change definitions to match.
(RETURN_IN_MEMORY): If !TARGET_AIX_STRUCT_RET, return
structures of size <= 8 bytes in registers.
(PRINT_OPERAND_PUNCT_VALID_P): Take out '$' and '*'.
* config/rs6000/rs6000.c (rs6000_long_double_size_string,
rs6000_long_double_type_size, rs6000_altivec_abi): New
globals.
(rs6000_override_options): Set rs6000_long_double_type_size
from rs6000_long_double_size_string, if nonzero. Set the
MASK_AIX_STRUCT_RET bit in target_flags from DEFAULT_ABI, if
not already set.
(rs6000_parse_abi_options): Set rs6000_altivec_abi, not a
target_flags bit.
(rs6000_init_builtins): This hook now takes no arguments.
* config/rs6000/netbsd.h, config/rs6000/linux.h: Define
DRAFT_V4_STRUCT_RET to 1.
===================================================================
Index: config/rs6000/linux.h
--- config/rs6000/linux.h 2001/11/15 05:21:06 1.30
+++ config/rs6000/linux.h 2001/12/03 00:00:17
@@ -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/12/03 00:00:17
@@ -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/12/02 08:29:22 1.248
+++ config/rs6000/rs6000.c 2001/12/03 00:00:18
@@ -68,6 +68,13 @@ struct rs6000_cpu_select rs6000_select[3
{ (const char *)0, "-mtune=", 1, 0 },
};
+/* Size of long double */
+const char *rs6000_long_double_size_string;
+int rs6000_long_double_type_size;
+
+/* Whether -mabi=altivec has appeared */
+int rs6000_altivec_abi;
+
/* Set to non-zero once AIX common-mode calls have been defined. */
static int common_mode_defined;
@@ -150,7 +157,7 @@ static int rs6000_adjust_cost PARAMS ((r
static int rs6000_adjust_priority PARAMS ((rtx, int));
static int rs6000_issue_rate PARAMS ((void));
-static void rs6000_init_builtins PARAMS ((tree));
+static void rs6000_init_builtins PARAMS ((void));
static void altivec_init_builtins PARAMS ((void));
static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
static rtx altivec_expand_builtin PARAMS ((tree, rtx));
@@ -475,6 +482,19 @@ rs6000_override_options (default_cpu)
error ("Unknown -mdebug-%s switch", rs6000_debug_name);
}
+ /* Set size of long double */
+ rs6000_long_double_type_size = 64;
+ if (rs6000_long_double_size_string)
+ {
+ char *tail;
+ int size = strtol (rs6000_long_double_size_string, &tail, 10);
+ if (*tail != '\0' || (size != 64 && size != 128))
+ error ("Unknown switch -mlong-double-%s",
+ rs6000_long_double_size_string);
+ else
+ rs6000_long_double_type_size = size;
+ }
+
/* Handle -mabi= options. */
rs6000_parse_abi_options ();
@@ -489,6 +509,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 ();
@@ -510,7 +541,7 @@ rs6000_parse_abi_options ()
if (rs6000_abi_string == 0)
return;
else if (! strcmp (rs6000_abi_string, "altivec"))
- target_flags |= MASK_ALTIVEC_ABI;
+ rs6000_altivec_abi = 1;
else
error ("Unknown ABI specified: '%s'", rs6000_abi_string);
}
@@ -3322,8 +3353,7 @@ rs6000_expand_builtin (exp, target, subt
}
static void
-rs6000_init_builtins (list_node)
- tree list_node ATTRIBUTE_UNUSED;
+rs6000_init_builtins ()
{
if (TARGET_ALTIVEC)
altivec_init_builtins ();
===================================================================
Index: config/rs6000/rs6000.h
--- config/rs6000/rs6000.h 2001/12/02 08:29:22 1.148
+++ config/rs6000/rs6000.h 2001/12/03 00:00:19
@@ -213,12 +213,14 @@ extern int target_flags;
/* Use AltiVec instructions. */
#define MASK_ALTIVEC 0x00080000
-/* Enhance the current ABI with AltiVec extensions. */
-#define MASK_ALTIVEC_ABI 0x00100000
+/* Return small structures in memory (as the AIX ABI requires). */
+#define MASK_AIX_STRUCT_RET 0x00100000
+#define MASK_AIX_STRUCT_RET_SET 0x00200000
+
+/* The only remaining free bit is 0x00400000. sysv4.h uses
+ 0x00800000 -> 0x40000000, and 0x80000000 is not available
+ because target_flags is signed. */
-/* Use 128-bit long double. */
-#define MASK_LONG_DOUBLE_128 0x00200000
-
#define TARGET_POWER (target_flags & MASK_POWER)
#define TARGET_POWER2 (target_flags & MASK_POWER2)
#define TARGET_POWERPC (target_flags & MASK_POWERPC)
@@ -238,8 +240,7 @@ extern int target_flags;
#define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD)
#define TARGET_SCHED_PROLOG (target_flags & MASK_SCHED_PROLOG)
#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)
@@ -344,10 +345,6 @@ extern int target_flags;
N_("Generate fused multiply/add instructions")},\
{"no-fused-madd", MASK_NO_FUSED_MADD, \
N_("Don't generate fused multiply/add instructions")},\
- {"long-double-64", -MASK_LONG_DOUBLE_128, \
- N_("Use 64 bit long doubles") }, \
- {"long-double-128", MASK_LONG_DOUBLE_128, \
- N_("Use 128 bit long doubles") }, \
{"sched-prolog", MASK_SCHED_PROLOG, \
""}, \
{"no-sched-prolog", -MASK_SCHED_PROLOG, \
@@ -356,6 +353,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, \
""}}
@@ -431,6 +440,8 @@ extern enum processor_type rs6000_cpu;
N_("Schedule code for given CPU") }, \
{"debug=", &rs6000_debug_name, N_("Enable debug output") }, \
{"abi=", &rs6000_abi_string, N_("Specify ABI to use") }, \
+ {"long-double-", &rs6000_long_double_size_string, \
+ N_("Specify size of long double (64 or 128 bits)") }, \
SUBTARGET_OPTIONS \
}
@@ -454,6 +465,15 @@ extern int rs6000_debug_arg; /* debug a
#define TARGET_DEBUG_STACK rs6000_debug_stack
#define TARGET_DEBUG_ARG rs6000_debug_arg
+/* These are separate from target_flags because we've run out of bits
+ there. */
+extern const char *rs6000_long_double_size_string;
+extern int rs6000_long_double_type_size;
+extern int rs6000_altivec_abi;
+
+#define TARGET_LONG_DOUBLE_128 (rs6000_long_double_type_size == 128)
+#define TARGET_ALTIVEC_ABI rs6000_altivec_abi
+
/* Sometimes certain combinations of command options do not make sense
on a particular target machine. You can define a macro
`OVERRIDE_OPTIONS' to take account of this. This macro, if
@@ -583,7 +603,7 @@ extern int rs6000_debug_arg; /* debug a
/* A C expression for the size in bits of the type `long double' on
the target machine. If you don't define this, the default is two
words. */
-#define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64)
+#define LONG_DOUBLE_TYPE_SIZE rs6000_long_double_type_size
/* Constant which presents upper bound of the above value. */
#define MAX_LONG_DOUBLE_TYPE_SIZE 128
@@ -1458,14 +1478,22 @@ typedef struct rs6000_stack {
&& 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
@@ -2773,7 +2801,7 @@ do { \
/* Define which CODE values are valid. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
- ((CODE) == '.' || (CODE) == '*' || (CODE) == '$')
+ ((CODE) == '.')
/* Print a memory address as an operand to reference that memory location. */