OSDN Git Service

PR target/34814
authorbergner <bergner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 26 Jan 2008 17:18:35 +0000 (17:18 +0000)
committerbergner <bergner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 26 Jan 2008 17:18:35 +0000 (17:18 +0000)
* 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 (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.
(UNSPEC_MOVSD_LOAD): New constant.
(UNSPEC_MOVSD_STORE): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@131869 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cfgexpand.c
gcc/config/rs6000/dfp.md
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/doc/tm.texi
gcc/function.c
gcc/function.h
gcc/target-def.h
gcc/target.h

index 13135a9..6a6e9fc 100644 (file)
@@ -1,3 +1,58 @@
+2007-01-26  Peter Bergner  <bergner@vnet.ibm.com>
+           Janis Johnson  <janis187@us.ibm.com>
+
+       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 (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.
+       (UNSPEC_MOVSD_LOAD): New constant.
+       (UNSPEC_MOVSD_STORE): Likewise.
+
 2008-01-26  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/34965
index 0a4e2ca..d22facb 100644 (file)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #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 fa20f7d..2d111b8 100644 (file)
 ;; 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" "")))]
    (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 4c031e7..762f784 100644 (file)
@@ -103,6 +103,7 @@ extern void rs6000_fatal_bad_address (rtx);
 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 83d8dbd..586c481 100644 (file)
@@ -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_info (tree, rtx, int)
      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;
 \f
 
@@ -1240,7 +1253,6 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
     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_mode mode)
        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, enum machine_mode mode)
       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, enum machine_mode mode)
     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, enum machine_mode mode)
 /* 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 *cum, enum machine_mode mode,
     {
       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 *cum, enum machine_mode mode,
       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 machine_mode mode,
       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, tree type, tree *pre_p, tree *post_p)
       && (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, tree type, tree *pre_p, tree *post_p)
       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, tree type, tree *pre_p, tree *post_p)
       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 mem2)
   return 1;
 }
 \f
+
+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.  */
@@ -11115,7 +11284,7 @@ rs6000_secondary_reload_class (enum reg_class class,
   /* Constants, memory, and FP registers can go into FP registers.  */
   if ((regno == -1 || FP_REGNO_P (regno))
       && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
-    return NO_REGS;
+    return (mode != SDmode) ? NO_REGS : GENERAL_REGS;
 
   /* Memory, and AltiVec registers can go into AltiVec registers.  */
   if ((regno == -1 || ALTIVEC_REGNO_P (regno))
@@ -16727,6 +16896,7 @@ rs6000_output_function_epilogue (FILE *file,
                      switch (mode)
                        {
                        case SFmode:
+                       case SDmode:
                          bits = 0x2;
                          break;
 
@@ -21513,29 +21683,9 @@ rs6000_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
       || 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 +21726,9 @@ rs6000_libcall_value (enum machine_mode 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 f820cf0..6a64eae 100644 (file)
@@ -622,7 +622,7 @@ extern enum rs6000_nop_insertion rs6000_sched_insert_nops;
 #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))
 \f
@@ -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 e644922..74aa90c 100644 (file)
@@ -1502,6 +1502,20 @@ Returns true if the target supports decimal floating point.
 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 d89a040..401bb21 100644 (file)
@@ -1568,8 +1568,8 @@ instantiate_virtual_regs_in_insn (rtx insn)
 /* 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_subtrees, void *data ATTRIBUTE_UNUSED)
     {
       *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 abc2303..fbaa17d 100644 (file)
@@ -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 e15b5d9..118e979 100644 (file)
 #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
   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 12b01da..128a029 100644 (file)
@@ -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