[PATCH][UPDATED] PR target/34814 Force SDmode function args into FP registers per the ABI

Peter Bergner bergner@vnet.ibm.com
Fri Jan 25 10:06:00 GMT 2008


On Thu, Jan 24, 2008 at 11:54:41AM -0800, Ian Lance Taylor wrote:
> I'm not very good with names.  This is really a hook--it doesn't
> really have anything to do with variables--so maybe something like
> expand_to_rtl_hook?  I hope somebody else has a better suggestion.

Ian / David,

Here's an updated patch that I'm bootstrapping and regtesting now.
Is this ok assuming no bootstrap or regresstion problems?


Peter

	PR target/34814
	* doc/tm.texi (TARGET_EXPAND_TO_RTL_HOOK): Document.
	(TARGET_INSTANTIATE_DECLS): Likewise.
	* target.h (expand_to_rtl_hook): New target hook.
	(instantiate_decls): Likewise.
	* function.c (instantiate_decl): Make non-static.  Rename to...
	(instantiate_decl_rtl): ... this.
	(instantiate_expr): Use instantiate_decl_rtl.
	(instantiate_decls_1): Likewise.
	(instantiate_decls): Likewise.
	(instantiate_virtual_regs: Call new instantiate_decls taget hook.
	* function.h (instantiate_decl_rtl): Add prototype.
	* cfgexpand.c (target.h): New include.
	(tree_expand_cfg): Call new expand_to_rtl_hook target hook.
	* target-def.h (TARGET_EXPAND_TO_RTL_HOOK): New define.
	(TARGET_INSTANTIATE_DECLS): Likewise.
	(TARGET_INITIALIZER): New target hooks added.
	* config/rs6000/rs6000-protos.h (rs6000_secondary_memory_needed_rtx):
	New prototype.
	* config/rs6000/rs6000.c (tree-flow.h): New include.
	(machine_function): Add sdmode_stack_slot field.
	(rs6000_alloc_sdmode_stack_slot): New function.
	(rs6000_instantiate_decls): Likewise.
	(rs6000_secondary_memory_needed_rtx): Likewise.
	(rs6000_check_sdmode): Likewise.
	(TARGET_EXPAND_TO_RTL_HOOK): Target macro defined.
	(TARGET_INSTANTIATE_DECLS): Likewise.
	(rs6000_hard_regno_mode_ok): Allow SDmode.
	(num_insns_constant): Likewise.  Handle _Decimal32 constants.
	(rs6000_emit_move): Handle SDmode.
	(function_arg_advance): Likewise.
	(function_arg): Likewise.
	(rs6000_gimplify_va_arg): Likewise.  Add special handling of
	SDmode var args for 32-bit compiles.
	(rs6000_secondary_reload_class): Handle SDmode.
	(rs6000_output_function_epilogue): Likewise.
	(rs6000_function_value): Simplify if statement.
	(rs6000_libcall_value): Likewise.
	* config/rs6000/rs6000.h (SLOW_UNALIGNED_ACCESS): Handle SDmode.
	(SECONDARY_MEMORY_NEEDED_RTX): Add define.
	* config/rs6000/dfp.md (UNSPEC_MOVSD_LOAD): New constant.
	(UNSPEC_MOVSD_STORE): Likewise.
	(movsd): New define_expand and splitter.
	(movsd_hardfloat): New define_insn.
	(movsd_softfloat): Likewise.
	(movsd_store): Likewise.
	(movsd_load): Likewise.
	(extendsddd2): Likewise.
	(extendsdtd2): Likewise.
	(truncddsd2): Likewise.
	(movdd_hardfloat64): Fixup comment.

Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 131741)
+++ gcc/doc/tm.texi	(working copy)
@@ -1507,6 +1507,20 @@ Returns true if the target supports deci
 Returns true if the target supports fixed-point arithmetic.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_EXPAND_TO_RTL_HOOK (void)
+This hook is called just before expansion into rtl, allowing the target
+to perform additional initializations or analysis before the expansion.
+For example, the rs6000 port uses it to allocate a scratch stack slot
+for use in copying SDmode values between memory and floating point
+registers whenever the function being expanded has any SDmode
+usage.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_INSTANTIATE_DECLS (void)
+This hook allows the backend to perform additional instantiations on rtl
+that are not actually in any insns yet, but will be later.
+@end deftypefn
+
 @deftypefn {Target Hook} {const char *} TARGET_MANGLE_TYPE (tree @var{type})
 If your target defines any fundamental types, or any types your target
 uses should be mangled differently from the default, define this hook
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 131741)
+++ gcc/target.h	(working copy)
@@ -849,6 +849,15 @@ struct gcc_target
 				      enum machine_mode,
 				      struct secondary_reload_info *);
 
+  /* This target hook allows the backend to perform additional
+     processing while initializing for variable expansion.  */
+  void (* expand_to_rtl_hook) (void);
+
+  /* This target hook allows the backend to perform additional
+     instantiations on rtx that are not actually in insns yet,
+     but will be later.  */
+  void (* instantiate_decls) (void);
+
   /* Functions specific to the C family of frontends.  */
   struct c {
     /* Return machine mode for non-standard suffix
Index: gcc/function.c
===================================================================
--- gcc/function.c	(revision 131741)
+++ gcc/function.c	(working copy)
@@ -1568,8 +1568,8 @@ instantiate_virtual_regs_in_insn (rtx in
 /* Subroutine of instantiate_decls.  Given RTL representing a decl,
    do any instantiation required.  */
 
-static void
-instantiate_decl (rtx x)
+void
+instantiate_decl_rtl (rtx x)
 {
   rtx addr;
 
@@ -1579,8 +1579,8 @@ instantiate_decl (rtx x)
   /* If this is a CONCAT, recurse for the pieces.  */
   if (GET_CODE (x) == CONCAT)
     {
-      instantiate_decl (XEXP (x, 0));
-      instantiate_decl (XEXP (x, 1));
+      instantiate_decl_rtl (XEXP (x, 0));
+      instantiate_decl_rtl (XEXP (x, 1));
       return;
     }
 
@@ -1610,7 +1610,7 @@ instantiate_expr (tree *tp, int *walk_su
     {
       *walk_subtrees = 0;
       if (DECL_P (t) && DECL_RTL_SET_P (t))
-	instantiate_decl (DECL_RTL (t));
+	instantiate_decl_rtl (DECL_RTL (t));
     }
   return NULL;
 }
@@ -1626,7 +1626,7 @@ instantiate_decls_1 (tree let)
   for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
     {
       if (DECL_RTL_SET_P (t))
-	instantiate_decl (DECL_RTL (t));
+	instantiate_decl_rtl (DECL_RTL (t));
       if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t))
 	{
 	  tree v = DECL_VALUE_EXPR (t);
@@ -1650,8 +1650,8 @@ instantiate_decls (tree fndecl)
   /* Process all parameters of the function.  */
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
     {
-      instantiate_decl (DECL_RTL (decl));
-      instantiate_decl (DECL_INCOMING_RTL (decl));
+      instantiate_decl_rtl (DECL_RTL (decl));
+      instantiate_decl_rtl (DECL_INCOMING_RTL (decl));
       if (DECL_HAS_VALUE_EXPR_P (decl))
 	{
 	  tree v = DECL_VALUE_EXPR (decl);
@@ -1715,6 +1715,8 @@ instantiate_virtual_regs (void)
   /* Instantiate the virtual registers in the DECLs for debugging purposes.  */
   instantiate_decls (current_function_decl);
 
+  targetm.instantiate_decls ();
+
   /* Indicate that, from now on, assign_stack_local should use
      frame_pointer_rtx.  */
   virtuals_instantiated = 1;
Index: gcc/function.h
===================================================================
--- gcc/function.h	(revision 131741)
+++ gcc/function.h	(working copy)
@@ -491,6 +491,7 @@ extern int trampolines_created;
 extern void set_cfun (struct function *new_cfun);
 extern void push_cfun (struct function *new_cfun);
 extern void pop_cfun (void);
+extern void instantiate_decl_rtl (rtx x);
 
 /* For backward compatibility... eventually these should all go away.  */
 #define current_function_pops_args (cfun->pops_args)
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	(revision 131741)
+++ gcc/cfgexpand.c	(working copy)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  
 #include "params.h"
 #include "tree-inline.h"
 #include "value-prof.h"
+#include "target.h"
 
 /* Verify that there is exactly single jump instruction since last and attach
    REG_BR_PROB note specifying probability.
@@ -1873,6 +1874,8 @@ tree_expand_cfg (void)
   /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE.  */
   discover_nonconstant_array_refs ();
 
+  targetm.expand_to_rtl_hook ();
+
   /* Expand the variables recorded during gimple lowering.  */
   expand_used_vars ();
 
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(revision 131741)
+++ gcc/target-def.h	(working copy)
@@ -604,6 +604,14 @@
 #define TARGET_SECONDARY_RELOAD default_secondary_reload
 #endif
 
+#ifndef TARGET_EXPAND_TO_RTL_HOOK
+#define TARGET_EXPAND_TO_RTL_HOOK hook_void_void
+#endif
+
+#ifndef TARGET_INSTANTIATE_DECLS
+#define TARGET_INSTANTIATE_DECLS hook_void_void
+#endif
+
 /* C specific.  */
 #ifndef TARGET_C_MODE_FOR_SUFFIX
 #define TARGET_C_MODE_FOR_SUFFIX default_mode_for_suffix
@@ -771,6 +779,8 @@
   TARGET_INVALID_UNARY_OP,			\
   TARGET_INVALID_BINARY_OP,			\
   TARGET_SECONDARY_RELOAD,			\
+  TARGET_EXPAND_TO_RTL_HOOK,			\
+  TARGET_INSTANTIATE_DECLS,			\
   TARGET_C,					\
   TARGET_CXX,					\
   TARGET_EXTRA_LIVE_ON_ENTRY,			\
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(revision 131741)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -103,6 +103,7 @@ extern void rs6000_fatal_bad_address (rt
 extern rtx create_TOC_reference (rtx);
 extern void rs6000_split_multireg_move (rtx, rtx);
 extern void rs6000_emit_move (rtx, rtx, enum machine_mode);
+extern rtx rs6000_secondary_memory_needed_rtx (enum machine_mode);
 extern rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode);
 extern rtx rs6000_legitimize_reload_address (rtx, enum machine_mode,
 					     int, int, int, int *);
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 131741)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -53,6 +53,7 @@
 #include "cfglayout.h"
 #include "sched-int.h"
 #include "tree-gimple.h"
+#include "tree-flow.h"
 #include "intl.h"
 #include "params.h"
 #include "tm-constrs.h"
@@ -125,6 +126,10 @@ typedef struct machine_function GTY(())
   /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
      varargs save area.  */
   HOST_WIDE_INT varargs_save_offset;
+  /* Temporary stack slot to use for SDmode copies.  This slot is
+     64-bits wide and is allocated early enough so that the offset
+     does not overflow the 16-bit load/store offset field.  */
+  rtx sdmode_stack_slot;
 } machine_function;
 
 /* Target cpu type */
@@ -754,6 +759,8 @@ static void rs6000_elf_encode_section_in
      ATTRIBUTE_UNUSED;
 #endif
 static bool rs6000_use_blocks_for_constant_p (enum machine_mode, const_rtx);
+static void rs6000_alloc_sdmode_stack_slot (void);
+static void rs6000_instantiate_decls (void);
 #if TARGET_XCOFF
 static void rs6000_xcoff_asm_output_anchor (rtx);
 static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
@@ -1221,6 +1228,12 @@ static const char alt_reg_names[][8] =
 #undef TARGET_BUILTIN_RECIPROCAL
 #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal
 
+#undef TARGET_EXPAND_TO_RTL_HOOK
+#define TARGET_EXPAND_TO_RTL_HOOK rs6000_alloc_sdmode_stack_slot
+
+#undef TARGET_INSTANTIATE_DECLS
+#define TARGET_INSTANTIATE_DECLS rs6000_instantiate_decls
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 
@@ -1240,7 +1253,6 @@ rs6000_hard_regno_mode_ok (int regno, en
     return
       ((SCALAR_FLOAT_MODE_P (mode)
        && (mode != TDmode || (regno % 2) == 0)
-       && mode != SDmode
        && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
       || (GET_MODE_CLASS (mode) == MODE_INT
 	  && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD)
@@ -2460,13 +2472,16 @@ num_insns_constant (rtx op, enum machine
 	return num_insns_constant_wide (INTVAL (op));
 
       case CONST_DOUBLE:
-	if (mode == SFmode)
+	if (mode == SFmode || mode == SDmode)
 	  {
 	    long l;
 	    REAL_VALUE_TYPE rv;
 
 	    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-	    REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+	    if (DECIMAL_FLOAT_MODE_P (mode))
+	      REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
+	    else
+	      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
 	    return num_insns_constant_wide ((HOST_WIDE_INT) l);
 	  }
 
@@ -4697,6 +4712,55 @@ rs6000_emit_move (rtx dest, rtx source, 
       return;
     }
 
+  if (reload_in_progress && cfun->machine->sdmode_stack_slot != NULL_RTX)
+    cfun->machine->sdmode_stack_slot =
+      eliminate_regs (cfun->machine->sdmode_stack_slot, VOIDmode, NULL_RTX);
+
+  if (reload_in_progress
+      && mode == SDmode
+      && MEM_P (operands[0])
+      && rtx_equal_p (operands[0], cfun->machine->sdmode_stack_slot)
+      && REG_P (operands[1]))
+    {
+      if (FP_REGNO_P (REGNO (operands[1])))
+	{
+	  rtx mem = adjust_address_nv (operands[0], DDmode, 0);
+	  mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+	  emit_insn (gen_movsd_store (mem, operands[1]));
+	}
+      else if (INT_REGNO_P (REGNO (operands[1])))
+	{
+	  rtx mem = adjust_address_nv (operands[0], mode, 4);
+	  mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+	  emit_insn (gen_movsd_hardfloat (mem, operands[1]));
+	}
+      else
+	gcc_unreachable();
+      return;
+    }
+  if (reload_in_progress
+      && mode == SDmode
+      && REG_P (operands[0])
+      && MEM_P (operands[1])
+      && rtx_equal_p (operands[1], cfun->machine->sdmode_stack_slot))
+    {
+      if (FP_REGNO_P (REGNO (operands[0])))
+	{
+	  rtx mem = adjust_address_nv (operands[1], DDmode, 0);
+	  mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+	  emit_insn (gen_movsd_load (operands[0], mem));
+	}
+      else if (INT_REGNO_P (REGNO (operands[0])))
+	{
+	  rtx mem = adjust_address_nv (operands[1], mode, 4);
+	  mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+	  emit_insn (gen_movsd_hardfloat (operands[0], mem));
+	}
+      else
+	gcc_unreachable();
+      return;
+    }
+
   /* FIXME:  In the long term, this switch statement should go away
      and be replaced by a sequence of tests based on things like
      mode == Pmode.  */
@@ -4717,6 +4781,7 @@ rs6000_emit_move (rtx dest, rtx source, 
     case DFmode:
     case DDmode:
     case SFmode:
+    case SDmode:
       if (CONSTANT_P (operands[1])
 	  && ! easy_fp_constant (operands[1], mode))
 	operands[1] = force_const_mem (mode, operands[1]);
@@ -4929,7 +4994,6 @@ rs6000_emit_move (rtx dest, rtx source, 
 /* Nonzero if we can use a floating-point register to pass this arg.  */
 #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
   (SCALAR_FLOAT_MODE_P (MODE)			\
-   && (MODE) != SDmode				\
    && (CUM)->fregno <= FP_ARG_MAX_REG		\
    && TARGET_HARD_FLOAT && TARGET_FPRS)
 
@@ -5409,7 +5473,7 @@ function_arg_advance (CUMULATIVE_ARGS *c
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
 	  && (mode == SFmode || mode == DFmode
-	      || mode == DDmode || mode == TDmode
+	      || mode == SDmode || mode == DDmode || mode == TDmode
 	      || (mode == TFmode && !TARGET_IEEEQUAD)))
 	{
 	  /* _Decimal128 must use an even/odd register pair.  This assumes
@@ -5476,7 +5540,6 @@ function_arg_advance (CUMULATIVE_ARGS *c
       cum->words = align_words + n_words;
 
       if (SCALAR_FLOAT_MODE_P (mode)
-	  && mode != SDmode
 	  && TARGET_HARD_FLOAT && TARGET_FPRS)
 	{
 	  /* _Decimal128 must be passed in an even/odd float register pair.
@@ -5978,7 +6041,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum
       if (TARGET_HARD_FLOAT && TARGET_FPRS
 	  && (mode == SFmode || mode == DFmode
 	      || (mode == TFmode && !TARGET_IEEEQUAD)
-	      || mode == DDmode || mode == TDmode))
+	      || mode == SDmode || mode == DDmode || mode == TDmode))
 	{
 	  /* _Decimal128 must use an even/odd register pair.  This assumes
 	     that the register number is odd when fregno is odd.  */
@@ -6652,6 +6715,7 @@ rs6000_gimplify_va_arg (tree valist, tre
       && (TYPE_MODE (type) == SFmode
 	  || TYPE_MODE (type) == DFmode
 	  || TYPE_MODE (type) == TFmode
+	  || TYPE_MODE (type) == SDmode
 	  || TYPE_MODE (type) == DDmode
 	  || TYPE_MODE (type) == TDmode))
     {
@@ -6660,7 +6724,7 @@ rs6000_gimplify_va_arg (tree valist, tre
       n_reg = (size + 7) / 8;
       sav_ofs = 8*4;
       sav_scale = 8;
-      if (TYPE_MODE (type) != SFmode)
+      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
 	align = 8;
     }
   else
@@ -6724,6 +6788,11 @@ rs6000_gimplify_va_arg (tree valist, tre
       u = build2 (MULT_EXPR, sizetype, u, size_int (sav_scale));
       t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t, u);
 
+      /* _Decimal32 varargs are located in the second word of the 64-bit
+	 FP register for 32-bit binaries.  */
+      if (!TARGET_POWERPC64 && TYPE_MODE (type) == SDmode)
+	t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+
       t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
       gimplify_and_add (t, pre_p);
 
@@ -11055,6 +11124,106 @@ mems_ok_for_quad_peep (rtx mem1, rtx mem
   return 1;
 }
 
+
+rtx
+rs6000_secondary_memory_needed_rtx (enum machine_mode mode)
+{
+  static bool eliminated = false;
+  if (mode != SDmode)
+    return assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+  else
+    {
+      rtx mem = cfun->machine->sdmode_stack_slot;
+      gcc_assert (mem != NULL_RTX);
+
+      if (!eliminated)
+	{
+	  mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+	  cfun->machine->sdmode_stack_slot = mem;
+	  eliminated = true;
+	}
+      return mem;
+    }
+}
+
+static tree
+rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+  /* Don't walk into types.  */
+  if (*tp == NULL_TREE || *tp == error_mark_node || TYPE_P (*tp))
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+
+  switch (TREE_CODE (*tp))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case FIELD_DECL:
+    case RESULT_DECL:
+    case REAL_CST:
+      if (TYPE_MODE (TREE_TYPE (*tp)) == SDmode)
+	return *tp;
+      break;
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+
+/* Allocate a 64-bit stack slot to be used for copying SDmode
+   values through if this function has any SDmode references.  */
+
+static void
+rs6000_alloc_sdmode_stack_slot (void)
+{
+  tree t;
+  basic_block bb;
+  block_stmt_iterator bsi;
+
+  gcc_assert (cfun->machine->sdmode_stack_slot == NULL_RTX);
+
+  FOR_EACH_BB (bb)
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+	tree ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
+						 rs6000_check_sdmode, NULL);
+	if (ret)
+	  {
+	    rtx stack = assign_stack_local (DDmode, GET_MODE_SIZE (DDmode), 0);
+	    cfun->machine->sdmode_stack_slot = adjust_address_nv (stack,
+								  SDmode, 0);
+	    return;
+	  }
+      }
+
+  /* Check for any SDmode parameters of the function.  */
+  for (t = DECL_ARGUMENTS (cfun->decl); t; t = TREE_CHAIN (t))
+    {
+      if (TREE_TYPE (t) == error_mark_node)
+	continue;
+
+      if (TYPE_MODE (TREE_TYPE (t)) == SDmode
+	  || TYPE_MODE (DECL_ARG_TYPE (t)) == SDmode)
+	{
+	  rtx stack = assign_stack_local (DDmode, GET_MODE_SIZE (DDmode), 0);
+	  cfun->machine->sdmode_stack_slot = adjust_address_nv (stack,
+								SDmode, 0);
+	  return;
+	}
+    }
+}
+
+static void
+rs6000_instantiate_decls (void)
+{
+  if (cfun->machine->sdmode_stack_slot != NULL_RTX)
+    instantiate_decl_rtl (cfun->machine->sdmode_stack_slot);
+}
+
 /* Return the register class of a scratch register needed to copy IN into
    or out of a register in CLASS in MODE.  If it can be done directly,
    NO_REGS is returned.  */
@@ -11106,6 +11275,22 @@ rs6000_secondary_reload_class (enum reg_
   else
     regno = -1;
 
+  if ((class != NO_REGS) && (mode == SDmode))
+    {
+      if (class == FLOAT_REGS)
+	{
+	  if (regno == -1 || FP_REGNO_P (regno))
+	    return GENERAL_REGS;
+	  return NO_REGS;
+	}
+      else if (class == GENERAL_REGS
+	       || class == BASE_REGS
+	       || class == SPECIAL_REGS)
+	return NO_REGS;
+
+      gcc_unreachable();
+    }
+
   /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
      into anything.  */
   if (class == GENERAL_REGS || class == BASE_REGS
@@ -16727,6 +16912,7 @@ rs6000_output_function_epilogue (FILE *f
 		      switch (mode)
 			{
 			case SFmode:
+			case SDmode:
 			  bits = 0x2;
 			  break;
 
@@ -21513,29 +21699,9 @@ rs6000_function_value (const_tree valtyp
       || POINTER_TYPE_P (valtype))
     mode = TARGET_32BIT ? SImode : DImode;
 
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS)
-	{
-	  switch (mode)
-	    {
-	    default:
-	      gcc_unreachable ();
-	    case SDmode:
-	      regno = GP_ARG_RETURN;
-	      break;
-	    case DDmode:
-	      regno = FP_ARG_RETURN;
-	      break;
-	    case TDmode:
-	      /* Use f2:f3 specified by the ABI.  */
-	      regno = FP_ARG_RETURN + 1;
-	      break;
-	    }
-	}
-      else
-	regno = GP_ARG_RETURN;
-    }
+  if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
+    /* _Decimal128 must use an even/odd register pair.  */
+    regno = (mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN;
   else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
   else if (TREE_CODE (valtype) == COMPLEX_TYPE
@@ -21576,29 +21742,9 @@ rs6000_libcall_value (enum machine_mode 
 				      GEN_INT (4))));
     }
 
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS)
-	{
-	  switch (mode)
-	    {
-	    default:
-	      gcc_unreachable ();
-	    case SDmode:
-	      regno = GP_ARG_RETURN;
-	      break;
-	    case DDmode:
-	      regno = FP_ARG_RETURN;
-	      break;
-	    case TDmode:
-	      /* Use f2:f3 specified by the ABI.  */
-	      regno = FP_ARG_RETURN + 1;
-	      break;
-	    }
-	}
-      else
-	regno = GP_ARG_RETURN;
-    }
+  if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
+    /* _Decimal128 must use an even/odd register pair.  */
+    regno = (mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN;
   else if (SCALAR_FLOAT_MODE_P (mode)
 	   && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 131741)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -622,7 +622,7 @@ extern enum rs6000_nop_insertion rs6000_
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN)				\
   (STRICT_ALIGNMENT							\
    || (((MODE) == SFmode || (MODE) == DFmode || (MODE) == TFmode	\
-	|| (MODE) == DDmode || (MODE) == TDmode				\
+	|| (MODE) == SDmode || (MODE) == DDmode || (MODE) == TDmode	\
 	|| (MODE) == DImode)						\
        && (ALIGN) < 32))
 
@@ -1173,6 +1173,13 @@ enum reg_class
 			   || (CLASS1) == ALTIVEC_REGS			\
 			   || (CLASS2) == ALTIVEC_REGS))
 
+/* For cpus that cannot load/store SDmode values from the 64-bit
+   FP registers without using a full 64-bit load/store, we need
+   to allocate a full 64-bit stack slot for them.  */
+
+#define SECONDARY_MEMORY_NEEDED_RTX(MODE) \
+  rs6000_secondary_memory_needed_rtx (MODE)
+
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS.
 
Index: gcc/config/rs6000/dfp.md
===================================================================
--- gcc/config/rs6000/dfp.md	(revision 131741)
+++ gcc/config/rs6000/dfp.md	(working copy)
@@ -20,6 +20,138 @@
 ;; along with GCC; see the file COPYING3.  If not see
 ;; <http://www.gnu.org/licenses/>.
 
+;;
+;; UNSPEC usage
+;;
+
+(define_constants
+  [(UNSPEC_MOVSD_LOAD		400)
+   (UNSPEC_MOVSD_STORE		401)
+  ])
+
+
+(define_expand "movsd"
+  [(set (match_operand:SD 0 "nonimmediate_operand" "")
+	(match_operand:SD 1 "any_operand" ""))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  "{ rs6000_emit_move (operands[0], operands[1], SDmode); DONE; }")
+
+(define_split
+  [(set (match_operand:SD 0 "gpc_reg_operand" "")
+	(match_operand:SD 1 "const_double_operand" ""))]
+  "reload_completed
+   && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+       || (GET_CODE (operands[0]) == SUBREG
+	   && GET_CODE (SUBREG_REG (operands[0])) == REG
+	   && REGNO (SUBREG_REG (operands[0])) <= 31))"
+  [(set (match_dup 2) (match_dup 3))]
+  "
+{
+  long l;
+  REAL_VALUE_TYPE rv;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+  REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
+
+  if (! TARGET_POWERPC64)
+    operands[2] = operand_subword (operands[0], 0, 0, SDmode);
+  else
+    operands[2] = gen_lowpart (SImode, operands[0]);
+
+  operands[3] = gen_int_mode (l, SImode);
+}")
+
+(define_insn "movsd_hardfloat"
+  [(set (match_operand:SD 0 "nonimmediate_operand" "=r,r,m,f,*c*l,*q,!r,*h,!r,!r")
+	(match_operand:SD 1 "input_operand"        "r,m,r,f,r,r,h,0,G,Fn"))]
+  "(gpc_reg_operand (operands[0], SDmode)
+   || gpc_reg_operand (operands[1], SDmode))
+   && (TARGET_HARD_FLOAT && TARGET_FPRS)"
+  "@
+   mr %0,%1
+   {l%U1%X1|lwz%U1%X1} %0,%1
+   {st%U0%X0|stw%U0%X0} %1,%0
+   fmr %0,%1
+   mt%0 %1
+   mt%0 %1
+   mf%1 %0
+   {cror 0,0,0|nop}
+   #
+   #"
+  [(set_attr "type" "*,load,store,fp,mtjmpr,*,mfjmpr,*,*,*")
+   (set_attr "length" "4,4,4,4,4,4,4,4,4,8")])
+
+(define_insn "movsd_softfloat"
+  [(set (match_operand:SD 0 "nonimmediate_operand" "=r,cl,q,r,r,m,r,r,r,r,r,*h")
+	(match_operand:SD 1 "input_operand" "r,r,r,h,m,r,I,L,R,G,Fn,0"))]
+  "(gpc_reg_operand (operands[0], SDmode)
+   || gpc_reg_operand (operands[1], SDmode))
+   && (TARGET_SOFT_FLOAT || !TARGET_FPRS)"
+  "@
+   mr %0,%1
+   mt%0 %1
+   mt%0 %1
+   mf%1 %0
+   {l%U1%X1|lwz%U1%X1} %0,%1
+   {st%U0%X0|stw%U0%X0} %1,%0
+   {lil|li} %0,%1
+   {liu|lis} %0,%v1
+   {cal|la} %0,%a1
+   #
+   #
+   {cror 0,0,0|nop}"
+  [(set_attr "type" "*,mtjmpr,*,mfjmpr,load,store,*,*,*,*,*,*")
+   (set_attr "length" "4,4,4,4,4,4,4,4,4,4,8,4")])
+
+(define_insn "movsd_store"
+  [(set (match_operand:DD 0 "nonimmediate_operand" "=m")
+	(unspec:DD [(match_operand:SD 1 "input_operand" "f")]
+		   UNSPEC_MOVSD_STORE))]
+  "(gpc_reg_operand (operands[0], DDmode)
+   || gpc_reg_operand (operands[1], SDmode))
+   && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "stfd%U0%X0 %1,%0"
+  [(set_attr "type" "fpstore")
+   (set_attr "length" "4")])
+
+(define_insn "movsd_load"
+  [(set (match_operand:SD 0 "nonimmediate_operand" "=f")
+	(unspec:SD [(match_operand:DD 1 "input_operand" "m")]
+		   UNSPEC_MOVSD_LOAD))]
+  "(gpc_reg_operand (operands[0], SDmode)
+   || gpc_reg_operand (operands[1], DDmode))
+   && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "lfd%U1%X1 %0,%1"
+  [(set_attr "type" "fpload")
+   (set_attr "length" "4")])
+
+;; Hardware support for decimal floating point operations.
+
+(define_insn "extendsddd2"
+  [(set (match_operand:DD 0 "gpc_reg_operand" "=f")
+	(float_extend:DD (match_operand:SD 1 "gpc_reg_operand" "f")))]
+  "TARGET_DFP"
+  "dctdp %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_expand "extendsdtd2"
+  [(set (match_operand:TD 0 "gpc_reg_operand" "=f")
+	(float_extend:TD (match_operand:SD 1 "gpc_reg_operand" "f")))]
+  "TARGET_DFP"
+{
+  rtx tmp = gen_reg_rtx (DDmode);
+  emit_insn (gen_extendsddd2 (tmp, operands[1]));
+  emit_insn (gen_extendddtd2 (operands[0], tmp));
+  DONE;
+})
+
+(define_insn "truncddsd2"
+  [(set (match_operand:SD 0 "gpc_reg_operand" "=f")
+	(float_truncate:SD (match_operand:DD 1 "gpc_reg_operand" "f")))]
+  "TARGET_DFP"
+  "drsp %0,%1"
+  [(set_attr "type" "fp")])
+
 (define_expand "negdd2"
   [(set (match_operand:DD 0 "gpc_reg_operand" "")
 	(neg:DD (match_operand:DD 1 "gpc_reg_operand" "")))]
@@ -309,7 +441,7 @@ (define_insn "*movdd_hardfloat64_mfpgpr"
    (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
 
 ; ld/std require word-aligned displacements -> 'Y' constraint.
-; List Y->r and r->Y before r->r for reload.(define_insn "*movdd_hardfloat64"
+; List Y->r and r->Y before r->r for reload.
 (define_insn "*movdd_hardfloat64"
   [(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,f,f,m,*c*l,!r,*h,!r,!r,!r")
 	(match_operand:DD 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F"))]



More information about the Gcc-patches mailing list