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]

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


This patch fixes PR34814, where SDmode arguments were not being passed and
returned in floating point registers as specified in the powerpc-linux and
powerpc64-linux ABIs.  Given the upcoming 4.3 cutoff and some reload
problems, I am delaying adding support for -mcpu=power6 compiles to make
use of the 32-bit indexed load/store instructions to load/store SDmode
values directly to/from memory into the FP registers.  Instead, they use
the same mechanism non power6 compiles due and copy through the integer
registers and a 64-bit stack slot.  I'll tackle that for 4.4.

This has passed bootstrapping on powerpc64-linux and is currently regtesting.
Is this ok for mainline if there are no regressions in the testsuite?

Peter

	PR target/34814
	* targhooks.c (default_scan_vars): New function.
	(default_instantiate_decls): Likewise.
	* targhooks.h (default_scan_vars): Add prototype;
	(default_instantiate_decls): Likewise.
	* target.h (scan_vars): 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 scan_vars target hook.
	* target-def.h (TARGET_SCAN_VARS): 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_SCAN_VARS): 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 (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.
	* config/rs6000/rs6000.md (UNSPEC_MOVSD_LOAD): New constant.
	(UNSPEC_MOVSD_STORE): Likewise.

Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 131741)
+++ gcc/targhooks.c	(working copy)
@@ -701,4 +701,20 @@ default_builtin_vector_alignment_reachab
   return true;
 }
 
+/* By default, do nothing. */
+
+void
+default_scan_vars (void)
+{
+  return;
+}
+
+/* By default, do nothing. */
+
+void
+default_instantiate_decls (void)
+{
+  return;
+}
+
 #include "gt-targhooks.h"
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 131741)
+++ gcc/targhooks.h	(working copy)
@@ -94,3 +94,5 @@ extern void hook_void_bitmap (bitmap);
 extern bool default_handle_c_option (size_t, const char *, int);
 extern int default_reloc_rw_mask (void);
 extern tree default_mangle_decl_assembler_name (tree, tree);
+extern void default_scan_vars (void);
+extern void default_instantiate_decls (void);
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 (* scan_vars) (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.scan_vars ();
+
   /* 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_SCAN_VARS
+#define TARGET_SCAN_VARS default_scan_vars
+#endif
+
+#ifndef TARGET_INSTANTIATE_DECLS
+#define TARGET_INSTANTIATE_DECLS default_instantiate_decls
+#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_SCAN_VARS,				\
+  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_SCAN_VARS
+#define TARGET_SCAN_VARS 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)
+    {
+      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;
+    }
+  else
+    return assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+}
+
+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.  */
@@ -11066,6 +11235,43 @@ rs6000_secondary_reload_class (enum reg_
 {
   int regno;
 
+  if ((class != NO_REGS) && (mode == SDmode))
+    {
+      int regno;
+
+      if (GET_CODE (in) == REG)
+	{
+	  regno = REGNO (in);
+	  if (regno >= FIRST_PSEUDO_REGISTER)
+	    {
+	      regno = true_regnum (in);
+	      if (regno >= FIRST_PSEUDO_REGISTER)
+		regno = -1;
+	    }
+	}
+      else if (GET_CODE (in) == SUBREG)
+	{
+	  regno = true_regnum (in);
+	  if (regno >= FIRST_PSEUDO_REGISTER)
+	    regno = -1;
+	}
+      else
+	regno = -1;
+
+      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();
+    }
+
   if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
 #if TARGET_MACHO
 		     && MACHOPIC_INDIRECT
@@ -16727,6 +16933,7 @@ rs6000_output_function_epilogue (FILE *f
 		      switch (mode)
 			{
 			case SFmode:
+			case SDmode:
 			  bits = 0x2;
 			  break;
 
@@ -21513,29 +21720,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 +21763,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,128 @@
 ;; along with GCC; see the file COPYING3.  If not see
 ;; <http://www.gnu.org/licenses/>.
 
+(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 +431,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"))]
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 131741)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -99,6 +99,8 @@ (define_constants
    (UNSPEC_DLMZB_CR		46)
    (UNSPEC_DLMZB_STRLEN		47)
    (UNSPEC_RSQRT		48)
+   (UNSPEC_MOVSD_LOAD		49)
+   (UNSPEC_MOVSD_STORE		50)
   ])
 
 ;;


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