]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
function.c (assign_parms): Split complex arguments.
authorAldy Hernandez <aldyh@redhat.com>
Tue, 3 Jun 2003 11:14:07 +0000 (11:14 +0000)
committerAldy Hernandez <aldyh@gcc.gnu.org>
Tue, 3 Jun 2003 11:14:07 +0000 (11:14 +0000)
2003-06-03  Aldy Hernandez  <aldyh@redhat.com>

        * function.c (assign_parms): Split complex arguments.

        * doc/tm.texi (SPLIT_COMPLEX_ARGS): Document.

        * expr.h (SPLIT_COMPLEX_ARGS): Define.
        (split_complex_types): Protoize.
        (split_complex_values): Protoize.

        * calls.c (expand_call): Split complex arguments on architectures
        that require it.
        (split_complex_values): New.
        (split_complex_types): New.

        * config/rs6000/rs6000.c (rs6000_libcall_value): New.
        (rs6000_function_value): Handle complex values on AIX.
        (rs6000_complex_function_value): New.

        * config/rs6000/rs6000-protos.h (rs6000_libcall_value): Protoize.

        * config/rs6000/rs6000.h (LIBCALL_VALUE): Call function.
        (SPLIT_COMPLEX_ARGS): New.

From-SVN: r67367

gcc/ChangeLog
gcc/calls.c
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/doc/tm.texi
gcc/expr.h
gcc/function.c

index 30b502ddb3a3f61e6839577c115e37940670c229..28fad05757acf945edf3a65709eaf96c1d33a63e 100644 (file)
@@ -1,3 +1,27 @@
+2003-06-03  Aldy Hernandez  <aldyh@redhat.com>
+
+        * function.c (assign_parms): Split complex arguments.
+
+        * doc/tm.texi (SPLIT_COMPLEX_ARGS): Document.
+
+        * expr.h (SPLIT_COMPLEX_ARGS): Define.
+        (split_complex_types): Protoize.
+        (split_complex_values): Protoize.
+
+        * calls.c (expand_call): Split complex arguments on architectures
+        that require it.
+        (split_complex_values): New.
+        (split_complex_types): New.
+
+        * config/rs6000/rs6000.c (rs6000_libcall_value): New.
+        (rs6000_function_value): Handle complex values on AIX.
+        (rs6000_complex_function_value): New.
+
+        * config/rs6000/rs6000-protos.h (rs6000_libcall_value): Protoize.
+
+        * config/rs6000/rs6000.h (LIBCALL_VALUE): Call function.
+        (SPLIT_COMPLEX_ARGS): New.
+
 2003-06-03  Jakub Jelinek  <jakub@redhat.com>
 
        * configure.in (HAVE_LD_PIE): Check for ld -pie.
index 9d7899c8bceebfb7d7cd9bf694aed3a95956cac9..4e95735376c671b8e1b341ce7b33aa9213542170 100644 (file)
@@ -2071,6 +2071,7 @@ expand_call (exp, target, ignore)
   rtx tail_call_insns = NULL_RTX;
   /* Data type of the function.  */
   tree funtype;
+  tree type_arg_types;
   /* Declaration of the function being called,
      or 0 if the function is computed (not known by name).  */
   tree fndecl = 0;
@@ -2306,6 +2307,16 @@ expand_call (exp, target, ignore)
     abort ();
   funtype = TREE_TYPE (funtype);
 
+  /* Munge the tree to split complex arguments into their imaginary
+     and real parts.  */
+  if (SPLIT_COMPLEX_ARGS)
+    {
+      type_arg_types = split_complex_types (TYPE_ARG_TYPES (funtype));
+      actparms = split_complex_values (actparms);
+    }
+  else
+    type_arg_types = TYPE_ARG_TYPES (funtype);
+
   /* See if this is a call to a function that can return more than once
      or a call to longjmp or malloc.  */
   flags |= special_function_p (fndecl, flags);
@@ -2359,9 +2370,9 @@ expand_call (exp, target, ignore)
 
   if ((STRICT_ARGUMENT_NAMING
        || ! PRETEND_OUTGOING_VARARGS_NAMED)
-      && TYPE_ARG_TYPES (funtype) != 0)
+      && type_arg_types != 0)
     n_named_args
-      = (list_length (TYPE_ARG_TYPES (funtype))
+      = (list_length (type_arg_types)
         /* Don't include the last named arg.  */
         - (STRICT_ARGUMENT_NAMING ? 0 : 1)
         /* Count the struct value address, if it is passed as a parm.  */
@@ -3447,6 +3458,82 @@ expand_call (exp, target, ignore)
 
   return target;
 }
+
+/* Traverse an argument list in VALUES and expand all complex
+   arguments into their components.  */
+tree
+split_complex_values (tree values)
+{
+  tree p;
+
+  values = copy_list (values);
+
+  for (p = values; p; p = TREE_CHAIN (p))
+    {
+      tree complex_value = TREE_VALUE (p);
+      tree complex_type;
+
+      complex_type = TREE_TYPE (complex_value);
+      if (!complex_type)
+       continue;
+
+      if (TREE_CODE (complex_type) == COMPLEX_TYPE)
+       {
+         tree subtype;
+         tree real, imag, next;
+
+         subtype = TREE_TYPE (complex_type);
+         complex_value = save_expr (complex_value);
+         real = build1 (REALPART_EXPR, subtype, complex_value);
+         imag = build1 (IMAGPART_EXPR, subtype, complex_value);
+
+         TREE_VALUE (p) = real;
+         next = TREE_CHAIN (p);
+         imag = build_tree_list (NULL_TREE, imag);
+         TREE_CHAIN (p) = imag;
+         TREE_CHAIN (imag) = next;
+
+         /* Skip the newly created node.  */
+         p = TREE_CHAIN (p);
+       }
+    }
+
+  return values;
+}
+
+/* Traverse a list of TYPES and expand all complex types into their
+   components.  */
+tree
+split_complex_types (tree types)
+{
+  tree p;
+
+  types = copy_list (types);
+
+  for (p = types; p; p = TREE_CHAIN (p))
+    {
+      tree complex_type = TREE_VALUE (p);
+
+      if (TREE_CODE (complex_type) == COMPLEX_TYPE)
+       {
+         tree next, imag;
+
+         /* Rewrite complex type with component type.  */
+         TREE_VALUE (p) = TREE_TYPE (complex_type);
+         next = TREE_CHAIN (p);
+
+         /* Add another component type for the imaginary part.  */
+         imag = build_tree_list (NULL_TREE, TREE_VALUE (p));
+         TREE_CHAIN (p) = imag;
+         TREE_CHAIN (imag) = next;
+
+         /* Skip the newly created node.  */
+         p = TREE_CHAIN (p);
+       }
+    }
+
+  return types;
+}
 \f
 /* Output a library call to function FUN (a SYMBOL_REF rtx).
    The RETVAL parameter specifies whether return value needs to be saved, other
index da75516de376e234416b23e9ef3db05ad436c6de..f088a045858b5689c4e49ebbf050a4db6fa56a01 100644 (file)
@@ -153,6 +153,7 @@ extern void setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *,
                                            enum machine_mode, tree,
                                            int *, int));
 extern rtx rs6000_function_value (tree, tree);
+extern rtx rs6000_libcall_value (enum machine_mode);
 extern struct rtx_def *rs6000_va_arg PARAMS ((tree, tree));
 extern int function_ok_for_sibcall PARAMS ((tree));
 #ifdef ARGS_SIZE_RTX
index f851e95af6ab72a8fb1e3727873dd6a5273230d1..2b9a76124e3f3b571831972ea38d47e39cb5ecc7 100644 (file)
@@ -312,6 +312,7 @@ static rtx rs6000_got_sym PARAMS ((void));
 static inline int rs6000_tls_symbol_ref_1 PARAMS ((rtx *, void *));
 static const char *rs6000_get_some_local_dynamic_name PARAMS ((void));
 static int rs6000_get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
+static rtx rs6000_complex_function_value (enum machine_mode);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -14361,6 +14362,33 @@ rs6000_memory_move_cost (mode, class, in)
     return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
 }
 
+/* Return an RTX representing where to find the function value of a
+   function returning MODE.  */
+static rtx
+rs6000_complex_function_value (enum machine_mode mode)
+{
+  unsigned int regno;
+  rtx r1, r2;
+  enum machine_mode inner = GET_MODE_INNER (mode);
+
+  if (FLOAT_MODE_P (mode))
+    regno = FP_ARG_RETURN;
+  else
+    {
+      regno = GP_ARG_RETURN;
+
+      /* 32-bit is OK since it'll go in r3/r4.  */
+      if (TARGET_32BIT)
+       return gen_rtx_REG (mode, regno);
+    }
+
+  r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
+                         const0_rtx);
+  r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
+                         GEN_INT (GET_MODE_UNIT_SIZE (inner)));
+  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
+}
+
 /* Define how to find the value returned by a function.
    VALTYPE is the data type of the value (as a tree).
    If the precise function being called is known, FUNC is its FUNCTION_DECL;
@@ -14386,6 +14414,10 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
 
   if (TREE_CODE (valtype) == REAL_TYPE && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
+  else if (TREE_CODE (valtype) == COMPLEX_TYPE
+          && TARGET_HARD_FLOAT
+          && SPLIT_COMPLEX_ARGS)
+    return rs6000_complex_function_value (mode);
   else if (TREE_CODE (valtype) == VECTOR_TYPE && TARGET_ALTIVEC)
     regno = ALTIVEC_ARG_RETURN;
   else
@@ -14394,6 +14426,26 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
   return gen_rtx_REG (mode, regno);
 }
 
+/* Define how to find the value returned by a library function
+   assuming the value has mode MODE.  */
+rtx
+rs6000_libcall_value (enum machine_mode mode)
+{
+  unsigned int regno;
+
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+          && TARGET_HARD_FLOAT && TARGET_FPRS)
+    regno = FP_ARG_RETURN;
+  else if (ALTIVEC_VECTOR_MODE (mode))
+    regno = ALTIVEC_ARG_RETURN;
+  else if (COMPLEX_MODE_P (mode) && SPLIT_COMPLEX_ARGS)
+    return rs6000_complex_function_value (mode);
+  else
+    regno = GP_ARG_RETURN;
+
+  return gen_rtx_REG (mode, regno);
+}
+
 /* Return true if TYPE is of type __ev64_opaque__.  */
 
 static bool
index d40626f5846e0d553f2a0a0f12c3a507b451892c..3edf959a511a4b51a747e75d4f80eea062fea118 100644 (file)
@@ -1583,11 +1583,7 @@ typedef struct rs6000_stack {
 /* Define how to find the value returned by a library function
    assuming the value has mode MODE.  */
 
-#define LIBCALL_VALUE(MODE)                                            \
-  gen_rtx_REG (MODE, ALTIVEC_VECTOR_MODE (MODE) ? ALTIVEC_ARG_RETURN   \
-                    : GET_MODE_CLASS (MODE) == MODE_FLOAT              \
-                    && TARGET_HARD_FLOAT && TARGET_FPRS                \
-                    ? FP_ARG_RETURN : GP_ARG_RETURN)
+#define LIBCALL_VALUE(MODE) rs6000_libcall_value ((MODE))
 
 /* The AIX ABI for the RS/6000 specifies that all structures are
    returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
@@ -1815,6 +1811,13 @@ typedef struct rs6000_args
 #define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
   function_arg_boundary (MODE, TYPE)
 
+/* Define to nonzero if complex arguments should be split into their
+   corresponding components.
+
+   This should be set for Linux and Darwin as well, but we can't break
+   the ABIs at the moment.  For now, only AIX gets fixed.  */
+#define SPLIT_COMPLEX_ARGS (DEFAULT_ABI == ABI_AIX)
+
 /* Perform any needed actions needed for a function that is receiving a
    variable number of arguments.
 
index 839cf108c227112dd535727a2030fc894d5f45d4..7215705eb808430d64d3b8b64d62a963dd964585 100644 (file)
@@ -3782,6 +3782,17 @@ the structure-value address.  On many machines, no registers can be
 used for this purpose since all function arguments are pushed on the
 stack.
 
+@findex SPLIT_COMPLEX_ARGS
+@item SPLIT_COMPLEX_ARGS
+
+Define this macro to a nonzero value if complex function arguments
+should be split into their corresponding components.  By default, GCC
+will attempt to pack complex arguments into the target's word size.
+Some ABIs require complex arguments to be split and treated as their
+individual components.  For example, on AIX64, complex floats should
+be passed in a pair of floating point registers, even though a complex
+float would fit in one 64-bit floating point register.
+
 @findex LOAD_ARGS_REVERSED
 @item LOAD_ARGS_REVERSED
 If defined, the order in which arguments are loaded into their
index 8cf5a8e5a6cf4030f39b2f44e92dba5a1b90d203..594df73a0d28b2c53b46b9b39e7a5dd423d9d8e6 100644 (file)
@@ -158,6 +158,14 @@ do {                                                       \
 #define FUNCTION_ARG_BOUNDARY(MODE, TYPE)      PARM_BOUNDARY
 #endif
 
+/* Define to nonzero if complex arguments should be split into their
+   corresponding components.  */
+#ifndef SPLIT_COMPLEX_ARGS
+#define SPLIT_COMPLEX_ARGS 0
+#endif
+tree split_complex_types (tree);
+tree split_complex_values (tree);
+
 /* Provide a default value for STRICT_ARGUMENT_NAMING.  */
 #ifndef STRICT_ARGUMENT_NAMING
 #define STRICT_ARGUMENT_NAMING 0
index 76184b9b659cdffef23f136599dbd9188c5c8ebc..c090d4aa869dac8b3f39caf4e63fb95719b5d790 100644 (file)
@@ -296,6 +296,7 @@ static void prepare_function_start PARAMS ((void));
 static void do_clobber_return_reg PARAMS ((rtx, void *));
 static void do_use_return_reg PARAMS ((rtx, void *));
 static void instantiate_virtual_regs_lossage PARAMS ((rtx));
+static tree split_complex_args (tree);
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
 static GTY(()) struct function *outer_function_chain;
@@ -4346,7 +4347,7 @@ assign_parms (fndecl)
      given as a constant and a tree-expression.  */
   struct args_size stack_args_size;
   tree fntype = TREE_TYPE (fndecl);
-  tree fnargs = DECL_ARGUMENTS (fndecl);
+  tree fnargs = DECL_ARGUMENTS (fndecl), orig_fnargs;
   /* This is used for the arg pointer when referring to stack args.  */
   rtx internal_arg_pointer;
   /* This is a dummy PARM_DECL that we used for the function result if
@@ -4400,9 +4401,14 @@ assign_parms (fndecl)
       fnargs = function_result_decl;
     }
 
+  orig_fnargs = fnargs;
+
   max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
   parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
 
+  if (SPLIT_COMPLEX_ARGS)
+    fnargs = split_complex_args (fnargs);
+
 #ifdef REG_PARM_STACK_SPACE
 #ifdef MAYBE_REG_PARM_STACK_SPACE
   reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
@@ -5189,6 +5195,35 @@ assign_parms (fndecl)
        }
     }
 
+  if (SPLIT_COMPLEX_ARGS)
+    {
+      parm = orig_fnargs;
+
+      for (; parm; parm = TREE_CHAIN (parm))
+       {
+         tree type = TREE_TYPE (parm);
+         
+         if (TREE_CODE (type) == COMPLEX_TYPE)
+           {
+             SET_DECL_RTL (parm,
+                           gen_rtx_CONCAT (DECL_MODE (parm),
+                                           DECL_RTL (fnargs),
+                                           DECL_RTL (TREE_CHAIN (fnargs))));
+             DECL_INCOMING_RTL (parm)
+               = gen_rtx_CONCAT (DECL_MODE (parm),
+                                 DECL_INCOMING_RTL (fnargs),
+                                 DECL_INCOMING_RTL (TREE_CHAIN (fnargs)));
+             fnargs = TREE_CHAIN (fnargs);
+           }
+         else
+           {
+             SET_DECL_RTL (parm, DECL_RTL (fnargs));
+             DECL_INCOMING_RTL (parm) = DECL_INCOMING_RTL (fnargs);
+           }
+         fnargs = TREE_CHAIN (fnargs);
+       }
+    }
+
   /* Output all parameter conversion instructions (possibly including calls)
      now that all parameters have been copied out of hard registers.  */
   emit_insn (conversion_insns);
@@ -5292,6 +5327,36 @@ assign_parms (fndecl)
        }
     }
 }
+
+static tree
+split_complex_args (tree args)
+{
+  tree p;
+
+  args = copy_list (args);
+
+  for (p = args; p; p = TREE_CHAIN (p))
+    {
+      tree complex_type = TREE_TYPE (p);
+
+      if (TREE_CODE (complex_type) == COMPLEX_TYPE)
+       {
+         tree decl;
+         tree subtype = TREE_TYPE (complex_type);
+
+         /* Rewrite the PARM_DECL's type with its component.  */
+         TREE_TYPE (p) = subtype;
+         DECL_ARG_TYPE (p) = TREE_TYPE (DECL_ARG_TYPE (p));
+
+         decl = build_decl (PARM_DECL, NULL_TREE, subtype);
+         DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (p);
+         TREE_CHAIN (decl) = TREE_CHAIN (p);
+         TREE_CHAIN (p) = decl;
+       }
+    }
+
+  return args;
+}
 \f
 /* Indicate whether REGNO is an incoming argument to the current function
    that was promoted to a wider mode.  If so, return the RTX for the