* gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Use
	tdep->ptr_value_regnum for pointer returns.
	(m68k_svr4_store_return_value): Likewise.
	(m68k_reg_struct_return_r): New, broken out of ...
	(m68k_reg_struct_return_p): ... here.  Implement gcc's structure
	mode algorithm.
	(m68k_svr4_init_abi, m68k_aout_init_abi): Set ptr_value_regnum.
	(m68k_gdbarch_init): Likewise.
	* gdb/m68k-tdep.h (struct gdbarch_tdep): Add ptr_value_regnum
	field.
diff --git a/ChangeLog.csl b/ChangeLog.csl
index c7dfa9c..4c6cab0 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,16 @@
+2006-06-08  Nathan Sidwell  <nathan@codesourcery.com>
+
+	* gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Use
+	tdep->ptr_value_regnum for pointer returns.
+	(m68k_svr4_store_return_value): Likewise.
+	(m68k_reg_struct_return_r): New, broken out of ...
+	(m68k_reg_struct_return_p): ... here.  Implement gcc's structure
+	mode algorithm.
+	(m68k_svr4_init_abi, m68k_aout_init_abi): Set ptr_value_regnum.
+	(m68k_gdbarch_init): Likewise.
+	* gdb/m68k-tdep.h (struct gdbarch_tdep): Add ptr_value_regnum
+	field.
+
 2006-06-05  Nathan Sidwell  <nathan@codesourcery.com>
 
 	* gdb/remote.c (remote_insert_watchpoint): Return -1, rather than
diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
index 73dfae80..1a4493f 100644
--- a/gdb/m68k-tdep.c
+++ b/gdb/m68k-tdep.c
@@ -265,11 +265,10 @@
       regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
       convert_typed_floating (buf, *tdep->fpreg_type, valbuf, type);
     }
-#if 0
-  /* GCC never differentiates pointer return types this way.  */
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
-    regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
-#endif
+    regcache_raw_read (regcache,
+		       gdbarch_tdep (current_gdbarch)->ptr_value_regnum,
+		       valbuf);
   else
     m68k_extract_return_value (type, regcache, valbuf);
 }
@@ -309,16 +308,79 @@
       regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
-    {
-      regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf);
-      regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf);
-    }
+    regcache_raw_write (regcache,
+			gdbarch_tdep (current_gdbarch)->ptr_value_regnum,
+			valbuf);
   else
     m68k_store_return_value (type, regcache, valbuf);
 }
 
 /* Return non-zero if TYPE, which is assumed to be a structure or
    union type, should be returned in registers for architecture
+   GDBARCH.
+   
+   Unfortunately GCC incorrectly implements this optimization.  Rather
+   than simply return all small structs, or even just those of size
+   2^N, it uses the mode of the structure to determine this.  BLKmode
+   structs will be returned by memory and QI,HI,SI,DI,SF&DF mode
+   structs will be returned by register.  For m68k a struct is BLKmode
+   unless it's size is 2^N and the mode for that size does not need a
+   greater alignment than the structure itself.  This is horrible.  */
+  
+
+static int
+m68k_reg_struct_return_r (struct type *type, int *align_p)
+{
+  enum type_code code = TYPE_CODE (type);
+  int len = TYPE_LENGTH (type);
+  int field_align = 1;
+  int my_align = len > 2 ? 2 : len;
+  int ix;
+  
+  if (code != TYPE_CODE_STRUCT && code != TYPE_CODE_UNION)
+    {
+      if (align_p && my_align > *align_p)
+	*align_p = my_align;
+      return 1;
+    }
+  
+  if ((len & -len) != len)
+    /* Length is not 2^n. */
+    return 0;
+
+  for (ix = 0; ix != TYPE_NFIELDS (type); ix++)
+    {
+      struct type *field_type;
+      int field_len;
+      
+      if (TYPE_FIELD_STATIC (type, ix))
+	/* Skip static fields.  */
+	continue;
+
+      field_type = TYPE_FIELD_TYPE (type, ix);
+      field_type = check_typedef (field_type);
+      field_len = TYPE_LENGTH (field_type);
+      
+      /* Look through arrays.  */
+      while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY)
+	{
+	  field_type = TYPE_TARGET_TYPE (field_type);
+	  field_type = check_typedef (field_type);
+	  field_len = TYPE_LENGTH (field_type);
+	}
+
+      if (!m68k_reg_struct_return_r (field_type, &field_align))
+	return 0;
+    }
+
+  if (align_p && field_align > *align_p)
+    *align_p = field_align;
+  
+  return align_p || my_align <= field_align;
+}
+
+/* Return non-zero if TYPE, which is assumed to be a structure or
+   union type, should be returned in registers for architecture
    GDBARCH.  */
 
 static int
@@ -336,88 +398,11 @@
   if (tdep->struct_return == pcc_struct_return)
     return 0;
 
-  /* Unfortunately GCC incorrectly implements this optimization.
-     Rather than simply return all small structs, or even just those
-     of size 2^N, it uses the mode of the structure to determine this.
-     BLKmode structs will be returned by memory and QI,HI,SI,DI,SF&DF
-     mode structs will be returned by register.  For m68k a struct is
-     BLKmode unless it's size is 2^N and the mode for that size does
-     not need a greater alignment than the structure itself.  Unions
-     will get the mode of last member whose size matches that of the
-     union itself.  This is horrible.  */
-  
-  if (len > 8 || (len & -len) != len)
-    /* Length is not 2^n or is too big. */
+  if (len > 8)
+    /* Length is too big. */
     return 0;
 
-  align = len > 4 ? 4 : len;
-  for (ix = 0; ix != TYPE_NFIELDS (type); ix++)
-    {
-      struct type *field_type;
-      int field_len;
-      
-      if (TYPE_FIELD_STATIC (type, ix))
-	/* Skip static fields.  */
-	continue;
-
-      field_type = TYPE_FIELD_TYPE (type, ix);
-      field_type = check_typedef (field_type);
-      field_len = TYPE_LENGTH (field_type);
-      
-      if (code == TYPE_CODE_STRUCT)
-	{
-	  /* Look through arrays.  */
-	  while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY)
-	    {
-	      field_type = TYPE_TARGET_TYPE (field_type);
-	      field_type = check_typedef (field_type);
-	      field_len = TYPE_LENGTH (field_type);
-	    }
-	  
-	  /* If the field's alignment is finer than the structs, we
-	     won't be in registers. */
-	  if (field_len < align)
-	    return 0;
-
-	  /* If the field itself is a struct or union, then check it
-	     can be passed in registers.  */
-	  if ((TYPE_CODE (field_type) == TYPE_CODE_STRUCT
-	       || TYPE_CODE (field_type) == TYPE_CODE_UNION)
-	      && !m68k_reg_struct_return_p (gdbarch, field_type))
-	    return 0;
-	}
-      else
-	{
-	  /* If this field accounts for the whole union, remember it.
-	     Note that we remember the last such field to match GCC's
-	     algorithm.  */
-	  if (field_len == len)
-	    union_field_type = field_type;
-	}
-    }
-
-  if (code == TYPE_CODE_UNION)
-    {
-      if (!union_field_type)
-	return 0;
-      /* Look through arrays. */
-      while (TYPE_CODE (union_field_type) == TYPE_CODE_ARRAY)
-	{
-	  union_field_type = TYPE_TARGET_TYPE (union_field_type);
-	  union_field_type = check_typedef (union_field_type);
-	}
-      /* If this field's alignment is too small, then we won't be in
-	 registers.  */
-      if (TYPE_LENGTH (union_field_type) < align)
-	return 0;
-      
-      if (TYPE_CODE (union_field_type) == TYPE_CODE_STRUCT
-	  || TYPE_CODE (union_field_type) == TYPE_CODE_UNION)
-	return m68k_reg_struct_return_p (gdbarch, union_field_type);
-    }
-  
-  /* It will be returned in registers */
-  return 1;
+  return m68k_reg_struct_return_r (type, NULL);
 }
 
 /* Determine, for architecture GDBARCH, how a return value of TYPE
@@ -1217,6 +1202,8 @@
   /* SVR4 uses %a0.  */
   tdep->struct_value_regnum = M68K_A0_REGNUM;
   tdep->struct_return = reg_struct_return;
+  /* Pointers are returned in %a0 */
+  tdep->ptr_value_regnum = M68K_A0_REGNUM;
 }
 
 /* a.out */
@@ -1228,8 +1215,11 @@
 
   set_gdbarch_return_value (gdbarch, m68k_return_value);
 
+  /* aout uses %a1 */
   tdep->struct_value_regnum = M68K_A1_REGNUM;
   tdep->struct_return = reg_struct_return;
+  /* Pointers are returned in %a0 */
+  tdep->ptr_value_regnum = M68K_A0_REGNUM;
 }
 
 
@@ -1286,6 +1276,7 @@
   set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
   tdep->struct_value_regnum = M68K_A0_REGNUM;
   tdep->struct_return = reg_struct_return;
+  tdep->ptr_value_regnum = M68K_D0_REGNUM;
   tdep->float_return = M68K_RETURN_FP0;
   tdep->fpreg_type = &M68K_FPREG_TYPE;
 
diff --git a/gdb/m68k-tdep.h b/gdb/m68k-tdep.h
index f68a903..15f4802 100644
--- a/gdb/m68k-tdep.h
+++ b/gdb/m68k-tdep.h
@@ -77,6 +77,9 @@
   /* Convention for returning structures.  */
   enum struct_return struct_return;
 
+  /* Register in which pointers are returned.  */
+  int ptr_value_regnum;
+
   /* Convention for returning floats.  zero in int regs, non-zero in float.  */
   int float_return;