re PR target/14567 ([3.4 only] long double and va_arg complex args)
authorAlan Modra <amodra@gcc.gnu.org>
Sat, 13 Mar 2004 07:14:12 +0000 (17:44 +1030)
committerAlan Modra <amodra@gcc.gnu.org>
Sat, 13 Mar 2004 07:14:12 +0000 (17:44 +1030)
PR target/14567
* config/rs6000/rs6000.h (UNITS_PER_ARG, RS6000_ARG_SIZE): Delete.
(HARD_REGNO_MODE_OK): Disallow TFmode for fp31.
* config/rs6000/rs6000.c (rs6000_arg_size): New function.
Update all users of RS6000_ARG_SIZE.
(function_arg_advance): Count fregno using mode size.
(function_arg): Handle long double split over regs and memory.
(function_arg_partial_nregs): Likewise.
(rs6000_va_arg): Repackage complex args.

From-SVN: r79436

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h

index 002ad1dc93aac9c631c5ff76cbfc5d2660ae08e0..33d6149cf8a44fbd92e4030983bf3f5df650b774 100644 (file)
@@ -1,3 +1,15 @@
+2004-03-13  Alan Modra  <amodra@bigpond.net.au>
+
+       PR target/14567
+       * config/rs6000/rs6000.h (UNITS_PER_ARG, RS6000_ARG_SIZE): Delete.
+       (HARD_REGNO_MODE_OK): Disallow TFmode for fp31.
+       * config/rs6000/rs6000.c (rs6000_arg_size): New function.
+       Update all users of RS6000_ARG_SIZE.
+       (function_arg_advance): Count fregno using mode size.
+       (function_arg): Handle long double split over regs and memory.
+       (function_arg_partial_nregs): Likewise.
+       (rs6000_va_arg): Repackage complex args.
+
 2004-03-13  Dean Ferreyra <dferreyra@igc.org>
 
        PR target/14047
@@ -54,7 +66,7 @@
        that corresponds to this FDE.
        (FRAME_BEGIN_LABEL): Allow target to override default label.
        (output_call_frame_info): If FDEs are linknonce, then use extra
-       indirection for FDE encoding, output a label for each FDE, and 
+       indirection for FDE encoding, output a label for each FDE, and
        output an empty label for each function without an FDE.
        (dwarf2out_begin_prologue): Set up decl field when creating an FDE.
        * varasm.c (globalize_decl): Call ASM_MAKE_LABEL_LINKONCE for
        * target.h (struct gcc_target): Move calls substructure before
        booleans.  Add split_complex_arg.
        * function.c (assign_parms, split_complex_args): Use it.
-        * calls.c (expand_call): Likewise.
-        (split_complex_values): Likewise.  Check for splittable types
-        before allocating memory.
-        (split_complex_types): Likewise.
+       * calls.c (expand_call): Likewise.
+       (split_complex_values): Likewise.  Check for splittable types
+       before allocating memory.
+       (split_complex_types): Likewise.
        * system.h (SPLIT_COMPLEX_ARGS): Poison.
        * expr.h (SPLIT_COMPLEX_ARGS): Remove.
        * target-def.h (TARGET_SPLIT_COMPLEX_ARG): New.
        (set_frame_base_location): Unshare variable if needed.
        (set_variable_part): Init the refcount of new variable.
        Unshare the variables if needed.
-       (delete_variable_part): Unshare the variables if needed. 
+       (delete_variable_part): Unshare the variables if needed.
        (emit_notes_for_differences_1): Init the refcount of new variable.
        (vt_add_function_parameters): Do not add function parameters to
        IN set of ENTRY_BLOCK_PTR because it is unused anyway.
        and gt_pch_use_address.
        * config/host-linux.c, config/host-solaris.c: New files.
        * config/x-linux, config/x-solaris: New files.
-       * config/rs6000/host-darwin.c darwin_rs6000_gt_pch_get_address): 
+       * config/rs6000/host-darwin.c (darwin_rs6000_gt_pch_get_address): 
        Update for changed definition.
        (darwin_rs6000_gt_pch_use_address): Likewise.
        * doc/hostconfig.texi: Update docs.
        PR bootstrap/12371
        * config/m68k/m68k.h (FIXED_REGISTERS): Add arg pointer.
        (CALL_USED_REGISTERS): Likewise.
-        (REG_CLASS_CONTENTS): Likewise.
+       (REG_CLASS_CONTENTS): Likewise.
        (REG_ALLOC_ORDER): New.
        (REGNO_REG_CLASS): Use regno_reg_class.
        * config/m68k/m68k.c: Add regno_reg_class array.
 
        * toplev.c (dump_file_tbl): Rename from dump_file.
        * bb-reorder.c, bt-load.c, cfgcleanup.c, cfglayout.c, cfgloopanal.c,
-       cfgloopmanip.c, cfgrtl.c, config/arm/arm.c, config/frv/frv.c,
+       cfgloopmanip.c, cfgrtl.c, config/arm/arm.c, config/frv/frv.c,
        config/i386/i386.c, config/ia64/ia64.c, config/mips/mips.c,
        config/sh/sh.c, cse.c, flow.c, ifcvt.c, loop-iv.c, loop-unroll.c,
        loop-unswitch.c, output.h, predict.c, profile.c, ra-build.c,
 
 2004-01-31  Paolo Bonzini  <bonzini@gnu.org>
 
-       * combine.c (cse_main): Set gen_lowpart to gen_lowpart_for_combine
+       * combine.c (cse_main): Set gen_lowpart to gen_lowpart_for_combine
        and restore it to gen_lowpart_general on exit.
        (gen_lowpart_for_combine): Adjust all callers to go through
        gen_lowpart.
 
        * fixinc/inclhack.def (alpha___extern_prefix,
        alpha___extern_prefix_standards): New hacks to obey
-       __PRAGMA_EXTERN_PREFIX.
+       __PRAGMA_EXTERN_PREFIX.
        * fixinc/tests/base/testing.h [ALPHA___EXTERN_PREFIX_CHECK]: New
        test.
        * fixinc/tests/base/standards.h: Likewise.
index 55774649e0e84eafa59ef4e68f7238bef286e7e3..56e4e7653cdbf72dc99f746f1aa618bbfe7a563d 100644 (file)
@@ -3979,6 +3979,24 @@ function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
   else
     return PARM_BOUNDARY;
 }
+
+/* Compute the size (in words) of a function argument.  */
+
+static unsigned long
+rs6000_arg_size (enum machine_mode mode, tree type)
+{
+  unsigned long size;
+
+  if (mode != BLKmode)
+    size = GET_MODE_SIZE (mode);
+  else
+    size = int_size_in_bytes (type);
+
+  if (TARGET_32BIT)
+    return (size + 3) >> 2;
+  else
+    return (size + 7) >> 3;
+}
 \f
 /* Update the data in CUM to advance over an argument
    of mode MODE and data type TYPE.
@@ -4019,7 +4037,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            align = ((6 - (cum->words & 3)) & 3);
          else
            align = cum->words & 1;
-         cum->words += align + RS6000_ARG_SIZE (mode, type);
+         cum->words += align + rs6000_arg_size (mode, type);
          
          if (TARGET_DEBUG_ARG)
            {
@@ -4046,7 +4064,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            {
              if (mode == DFmode)
                cum->words += cum->words & 1;
-             cum->words += RS6000_ARG_SIZE (mode, type);
+             cum->words += rs6000_arg_size (mode, type);
            }
        }
       else
@@ -4059,7 +4077,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
              || mode == TFmode)
            n_words = 1;
          else 
-           n_words = RS6000_ARG_SIZE (mode, type);
+           n_words = rs6000_arg_size (mode, type);
 
          /* Long long and SPE vectors are put in odd registers.  */
          if (n_words == 2 && (gregno & 1) == 0)
@@ -4096,11 +4114,11 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       int align = (TARGET_32BIT && (cum->words & 1) != 0
                   && function_arg_boundary (mode, type) == 64) ? 1 : 0;
 
-      cum->words += align + RS6000_ARG_SIZE (mode, type);
+      cum->words += align + rs6000_arg_size (mode, type);
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT
          && TARGET_HARD_FLOAT && TARGET_FPRS)
-       cum->fregno += (mode == TFmode ? 2 : 1);
+       cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
 
       if (TARGET_DEBUG_ARG)
        {
@@ -4122,7 +4140,7 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   if (cum->stdarg)
     {
       int gregno = cum->sysv_gregno;
-      int n_words = RS6000_ARG_SIZE (mode, type);
+      int n_words = rs6000_arg_size (mode, type);
 
       /* SPE vectors are put in odd registers.  */
       if (n_words == 2 && (gregno & 1) == 0)
@@ -4170,7 +4188,7 @@ rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                                               gen_rtx_REG (mode,
                                                            cum->fregno),
                                               const0_rtx)));
-      else if (align_words + RS6000_ARG_SIZE (mode, type)
+      else if (align_words + rs6000_arg_size (mode, type)
               > GP_ARG_NUM_REG)
        /* If this is partially on the stack, then we only
           include the portion actually in registers here.  */
@@ -4394,13 +4412,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
              || mode == TFmode)
            n_words = 1;
          else 
-           n_words = RS6000_ARG_SIZE (mode, type);
+           n_words = rs6000_arg_size (mode, type);
 
          /* Long long and SPE vectors are put in odd registers.  */
          if (n_words == 2 && (gregno & 1) == 0)
            gregno += 1;
 
-         /* Long long do not split between registers and stack.  */
+         /* Long long does not split between registers and stack.  */
          if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
            return gen_rtx_REG (mode, gregno);
          else
@@ -4422,39 +4440,69 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
       if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
-         if (! type
-             || ((cum->nargs_prototype > 0)
-                 /* IBM AIX extended its linkage convention definition always
-                    to require FP args after register save area hole on the
-                    stack.  */
-                 && (DEFAULT_ABI != ABI_AIX
-                     || ! TARGET_XL_CALL
-                     || (align_words < GP_ARG_NUM_REG))))
-           return gen_rtx_REG (mode, cum->fregno);
+         rtx fpr[2];
+         rtx *r;
+         bool needs_psave;
+         enum machine_mode fmode = mode;
+         int n;
+         unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
+
+         if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
+           {
+             /* Long double split over regs and memory.  */
+             if (fmode == TFmode)
+               fmode = DFmode;
+
+             /* Currently, we only ever need one reg here because complex
+                doubles are split.  */
+             if (cum->fregno != FP_ARG_MAX_REG - 1)
+               abort ();
+           }
+         fpr[1] = gen_rtx_REG (fmode, cum->fregno);
+
+         /* Do we also need to pass this arg in the parameter save
+            area?  */
+         needs_psave = (type
+                        && (cum->nargs_prototype <= 0
+                            || (DEFAULT_ABI == ABI_AIX
+                                && TARGET_XL_CALL
+                                && align_words >= GP_ARG_NUM_REG)));
+
+         if (!needs_psave && mode == fmode)
+           return fpr[1];
 
           if (TARGET_32BIT && TARGET_POWERPC64
               && mode == DFmode && cum->stdarg)
             return rs6000_mixed_function_arg (cum, mode, type, align_words);
 
-          return gen_rtx_PARALLEL (mode,
-           gen_rtvec (2,
-                      gen_rtx_EXPR_LIST (VOIDmode,
-                               ((align_words >= GP_ARG_NUM_REG)
-                                ? NULL_RTX
-                                : (align_words
-                                   + RS6000_ARG_SIZE (mode, type)
-                                   > GP_ARG_NUM_REG
-                                   /* If this is partially on the stack, then
-                                      we only include the portion actually
-                                      in registers here.  */
-                                   ? gen_rtx_REG (Pmode,
-                                              GP_ARG_MIN_REG + align_words)
-                                   : gen_rtx_REG (mode,
-                                              GP_ARG_MIN_REG + align_words))),
-                               const0_rtx),
-                      gen_rtx_EXPR_LIST (VOIDmode,
-                               gen_rtx_REG (mode, cum->fregno),
-                               const0_rtx)));
+         /* Describe where this piece goes.  */
+         r = fpr + 1;
+         *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
+         n = 1;
+
+         if (needs_psave)
+           {
+             /* Now describe the part that goes in gprs or the stack.
+                This piece must come first, before the fprs.  */
+             rtx reg = NULL_RTX;
+             if (align_words < GP_ARG_NUM_REG)
+               {
+                 unsigned long n_words = rs6000_arg_size (mode, type);
+                 enum machine_mode rmode = mode;
+
+                 if (align_words + n_words > GP_ARG_NUM_REG)
+                   /* If this is partially on the stack, then we only
+                      include the portion actually in registers here.
+                      We know this can only be one register because
+                      complex doubles are splt.  */
+                   rmode = Pmode;
+                 reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
+               }
+             *--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
+             ++n;
+           }
+
+         return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
        }
       else if (align_words < GP_ARG_NUM_REG)
        return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
@@ -4471,27 +4519,31 @@ int
 function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
                            tree type, int named)
 {
+  int ret = 0;
+
   if (DEFAULT_ABI == ABI_V4)
     return 0;
 
-  if (USE_FP_FOR_ARG_P (cum, mode, type)
-      || USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
+  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
+      && cum->nargs_prototype >= 0)
+    return 0;
+
+  if (USE_FP_FOR_ARG_P (cum, mode, type))
     {
-      if (cum->nargs_prototype >= 0)
+      if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
+       ret = FP_ARG_MAX_REG - cum->fregno;
+      else if (cum->nargs_prototype >= 0)
        return 0;
     }
 
   if (cum->words < GP_ARG_NUM_REG
-      && GP_ARG_NUM_REG < (cum->words + RS6000_ARG_SIZE (mode, type)))
-    {
-      int ret = GP_ARG_NUM_REG - cum->words;
-      if (ret && TARGET_DEBUG_ARG)
-       fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
+      && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
+    ret = GP_ARG_NUM_REG - cum->words;
 
-      return ret;
-    }
+  if (ret != 0 && TARGET_DEBUG_ARG)
+    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
 
-  return 0;
+  return ret;
 }
 \f
 /* A C expression that indicates when an argument must be passed by
@@ -4597,7 +4649,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       cfun->machine->sysv_varargs_p = 0;
 
       if (MUST_PASS_IN_STACK (mode, type))
-       first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type);
+       first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
     }
 
   set = get_varargs_alias_set ();
@@ -4787,8 +4839,42 @@ rs6000_va_arg (tree valist, tree type)
 
          return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
        }
-      else
-       return std_expand_builtin_va_arg (valist, type);
+      if (SPLIT_COMPLEX_ARGS
+         && TREE_CODE (type) == COMPLEX_TYPE)
+       {
+         tree elem_type = TREE_TYPE (type);
+         enum machine_mode elem_mode = TYPE_MODE (elem_type);
+         int elem_size = GET_MODE_SIZE (elem_mode);
+
+         if (elem_size < UNITS_PER_WORD)
+           {
+             rtx real_part, imag_part, dest_real, rr;
+
+             real_part = rs6000_va_arg (valist, elem_type);
+             imag_part = rs6000_va_arg (valist, elem_type);
+
+             /* We're not returning the value here, but the address.
+                real_part and imag_part are not contiguous, and we know
+                there is space available to pack real_part next to
+                imag_part.  float _Complex is not promoted to
+                double _Complex by the default promotion rules that
+                promote float to double.  */
+             if (2 * elem_size > UNITS_PER_WORD)
+               abort ();
+
+             real_part = gen_rtx_MEM (elem_mode, real_part);
+             imag_part = gen_rtx_MEM (elem_mode, imag_part);
+
+             dest_real = adjust_address (imag_part, elem_mode, -elem_size);
+             rr = gen_reg_rtx (elem_mode);
+             emit_move_insn (rr, real_part);
+             emit_move_insn (dest_real, rr);
+
+             return XEXP (dest_real, 0);
+           }
+       }
+
+      return std_expand_builtin_va_arg (valist, type);
     }
 
   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
index aceb56d4ffbbf0f0728bbd080725446132edd202..bd9d36bb53ec469cf37e6d8cbff22bff47d7f615 100644 (file)
@@ -1065,7 +1065,8 @@ extern const char *rs6000_warn_altivec_long_switch;
   (INT_REGNO_P (REGNO) ?                                               \
      INT_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1)          \
    : FP_REGNO_P (REGNO) ?                                              \
-     (GET_MODE_CLASS (MODE) == MODE_FLOAT                              \
+     ((GET_MODE_CLASS (MODE) == MODE_FLOAT                             \
+       && FP_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1))     \
       || (GET_MODE_CLASS (MODE) == MODE_INT                            \
          && GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD))                \
    : ALTIVEC_REGNO_P (REGNO) ? ALTIVEC_VECTOR_MODE (MODE)              \
@@ -1762,16 +1763,6 @@ typedef struct rs6000_args
   int sysv_gregno;             /* next available GP register */
 } CUMULATIVE_ARGS;
 
-/* Define intermediate macro to compute the size (in registers) of an argument
-   for the RS/6000.  */
-
-#define UNITS_PER_ARG (TARGET_32BIT ? 4 : 8)
-
-#define RS6000_ARG_SIZE(MODE, TYPE)                                    \
-((MODE) != BLKmode                                                     \
- ? (GET_MODE_SIZE (MODE) + (UNITS_PER_ARG - 1)) / UNITS_PER_ARG                \
- : (int_size_in_bytes (TYPE) + (UNITS_PER_ARG - 1)) / UNITS_PER_ARG)
-
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0.  */