This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix RETURN_IN_MEMORY for x86 Solaris


Many ia32 ports use the following definition of RETURN_IN_MEMORY:

#define RETURN_IN_MEMORY(TYPE) \
  (TYPE_MODE (TYPE) == BLKmode \
   || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8))

However, gcc ignores a false RETURN_IN_MEMORY if the specified return
register has call-saved parts.  For non-PIC, this means that only 12-byte
values are returned in general registers (i.e. (%eax, %edx, %ecx).)
Anything bigger than 12 bytes is be returned in memory because the
next register -- %ebx -- is call-saved.

The problem occurs for PIC, where %ebx is a fixed register, and is thus
in CALL_USED_REGISTERS.  PIC functions therefore try to return anything
up to 16 bytes in registers.  This is incompatible with non-PIC, and
fails to work anyway, because the function restores the PIC register
after it has set the %ebx return value.

This was fixed for i386.h by:

    r8212 | meissner | 1994-10-04 21:47:05 +0100 (Tue, 04 Oct 1994) | 2 lines

    Fix return complex doubles with -fpic clobbering %ebx

but the definition above differs in its treatment of vectors:
somewhat counter-intuitively, it returns 8-byte vectors in memory
for MMX and returns them in (general) registers otherwise.

The patch below defines a new function, ix86_sol10_return_in_memory,
that applies the same fix to the RETURN_IN_MEMORY definition above.
Specifically, it returns false for types bigger than 12 bytes if that
type is something that we'd return in general registers.  It therefore
keeps the non-PIC behaviour and makes the PIC behaviour compatible
with it.

The patch just replaces the Solaris definition for now; I'd rather not
change ports I can't test.  However, the patch does fix the same issue
for VxWorks, so if the patch is OK, I'll post a follow-up for that port.

ix86_sol10_return_in_memory might not be the best name given that it
can be used for other targets, but I couldn't think of a better one.
I hope it's not too bad as long as you think of it as "Solaris-like"
rather than "Solaris-only".  Suggestions welcome.

Tested on i686-solaris, where it fixes gcc.dg/torture/complex-alias-1.c
in a normal test run, and many failures for -fPIC tests.  OK to install?

Richard


gcc/
	* config/i386/i386-protos.h (ix86_sol10_return_in_memory): Declare.
	* config/i386/i386.c (ix86_sol10_return_in_memory): New function.
	* config/i386/sol2-10.h (RETURN_IN_MEMORY): Use it.

Index: gcc/config/i386/i386-protos.h
===================================================================
--- gcc/config/i386/i386-protos.h	(revision 123968)
+++ gcc/config/i386/i386-protos.h	(working copy)
@@ -134,6 +134,7 @@ extern bool ix86_function_value_regno_p 
 extern bool ix86_function_arg_regno_p (int);
 extern int ix86_function_arg_boundary (enum machine_mode, tree);
 extern int ix86_return_in_memory (tree);
+extern int ix86_sol10_return_in_memory (tree);
 extern void ix86_va_start (tree, rtx);
 extern rtx ix86_va_arg (tree, tree);
 
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 123968)
+++ gcc/config/i386/i386.c	(working copy)
@@ -4370,6 +4370,43 @@ ix86_return_in_memory (tree type)
     return return_in_memory_32 (type, mode);
 }
 
+/* Return false iff TYPE is returned in memory.  This version is used
+   on Solaris 10.  It is similar to the generic ix86_return_in_memory,
+   but differs notably in that when MMX is available, 8-byte vectors
+   are returned in memory, rather than in MMX registers.  */
+
+int 
+ix86_sol10_return_in_memory (tree type)
+{
+  int needed_intregs, needed_sseregs, size;
+  enum machine_mode mode = type_natural_mode (type);
+
+  if (TARGET_64BIT)
+    return return_in_memory_64 (type, mode);
+
+  if (mode == BLKmode)
+    return 1;
+
+  size = int_size_in_bytes (type);
+
+  if (VECTOR_MODE_P (mode))
+    {
+      /* Return in memory only if MMX registers *are* available.  This
+	 seems backwards, but it is consistent with the existing
+	 Solaris x86 ABI.  */
+      if (size == 8)
+	return TARGET_MMX;
+      if (size == 16)
+	return !TARGET_SSE;
+    }
+  else if (mode == TImode)
+    return !TARGET_SSE;
+  else if (mode == XFmode)
+    return 0;
+
+  return size > 12;
+}
+
 /* When returning SSE vector types, we have a choice of either
      (1) being abi incompatible with a -march switch, or
      (2) generating an error.
Index: gcc/config/i386/sol2-10.h
===================================================================
--- gcc/config/i386/sol2-10.h	(revision 123968)
+++ gcc/config/i386/sol2-10.h	(working copy)
@@ -111,12 +111,5 @@ #define LINK_ARCH_SPEC TARGET_LD_EMULATI
 #undef TARGET_ASM_NAMED_SECTION
 #define TARGET_ASM_NAMED_SECTION i386_solaris_elf_named_section
 
-/* In 32-bit mode, follow the SVR4 ABI definition; in 64-bit mode, use
-   the AMD64 ABI definition.  */
 #undef RETURN_IN_MEMORY
-#define RETURN_IN_MEMORY(TYPE)			\
-  (TARGET_64BIT 				\
-   ? ix86_return_in_memory (TYPE)		\
-   : (TYPE_MODE (TYPE) == BLKmode		\
-      || (VECTOR_MODE_P (TYPE_MODE (TYPE)) 	\
-	  && int_size_in_bytes (TYPE) == 8)))
+#define RETURN_IN_MEMORY ix86_sol10_return_in_memory


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]