OSDN Git Service

(call patterns): Use %. in cror.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 9ad7d16..edb0dd0 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
-   Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -119,6 +119,7 @@ int stack_arg_under_construction;
 #endif
 
 static int calls_function      PROTO((tree, int));
+static int calls_function_1    PROTO((tree, int));
 static void emit_call_1                PROTO((rtx, tree, int, int, rtx, rtx, int,
                                       rtx, int));
 static void store_one_arg      PROTO ((struct arg_data *, rtx, int, int,
@@ -132,11 +133,25 @@ static void store_one_arg PROTO ((struct arg_data *, rtx, int, int,
    arguments on the stack, but that is too difficult to compute, so we just
    assume any function call might require the stack.  */
 
+static tree calls_function_save_exprs;
+
 static int
 calls_function (exp, which)
      tree exp;
      int which;
 {
+  int val;
+  calls_function_save_exprs = 0;
+  val = calls_function_1 (exp, which);
+  calls_function_save_exprs = 0;
+  return val;
+}
+
+static int
+calls_function_1 (exp, which)
+     tree exp;
+     int which;
+{
   register int i;
   int type = TREE_CODE_CLASS (TREE_CODE (exp));
   int length = tree_code_length[(int) TREE_CODE (exp)];
@@ -167,7 +182,12 @@ calls_function (exp, which)
     case SAVE_EXPR:
       if (SAVE_EXPR_RTL (exp) != 0)
        return 0;
-      break;
+      if (value_member (exp, calls_function_save_exprs))
+       return 0;
+      calls_function_save_exprs = tree_cons (NULL_TREE, exp,
+                                            calls_function_save_exprs);
+      return (TREE_OPERAND (exp, 0) != 0
+             && calls_function_1 (TREE_OPERAND (exp, 0), which));
 
     case BLOCK:
       {
@@ -175,7 +195,7 @@ calls_function (exp, which)
 
        for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local))
          if (DECL_INITIAL (local) != 0
-             && calls_function (DECL_INITIAL (local), which))
+             && calls_function_1 (DECL_INITIAL (local), which))
            return 1;
       }
       {
@@ -184,7 +204,7 @@ calls_function (exp, which)
        for (subblock = BLOCK_SUBBLOCKS (exp);
             subblock;
             subblock = TREE_CHAIN (subblock))
-         if (calls_function (subblock, which))
+         if (calls_function_1 (subblock, which))
            return 1;
       }
       return 0;
@@ -203,7 +223,7 @@ calls_function (exp, which)
 
   for (i = 0; i < length; i++)
     if (TREE_OPERAND (exp, i) != 0
-       && calls_function (TREE_OPERAND (exp, i), which))
+       && calls_function_1 (TREE_OPERAND (exp, i), which))
       return 1;
 
   return 0;
@@ -473,6 +493,8 @@ expand_call (exp, target, ignore)
   CUMULATIVE_ARGS args_so_far;
   /* Nonzero if a reg parm has been scanned.  */
   int reg_parm_seen;
+  /* Nonzero if this is an indirect function call.  */
+  int current_call_is_indirect = 0;
 
   /* Nonzero if we must avoid push-insns in the args for this call. 
      If stack space is allocated for register parameters, but not by the
@@ -732,6 +754,15 @@ expand_call (exp, target, ignore)
   if (fndecl && DECL_NAME (fndecl))
     name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
 
+  /* On some machines (such as the PA) indirect calls have a different
+     calling convention than normal calls.  FUNCTION_ARG in the target
+     description can look at current_call_is_indirect to determine which
+     calling convention to use.  */
+  current_call_is_indirect = (fndecl == 0);
+#if 0
+    = TREE_CODE (TREE_OPERAND (exp, 0)) == NON_LVALUE_EXPR ? 1 : 0;
+#endif
+
 #if 0
   /* Unless it's a call to a specific function that isn't alloca,
      if it has one argument, we must assume it might be alloca.  */
@@ -915,41 +946,60 @@ expand_call (exp, target, ignore)
       if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type), type,
                                          argpos < n_named_args))
        {
-         /* We make a copy of the object and pass the address to the function
-            being called.  */
-         rtx copy;
-
-         if (TYPE_SIZE (type) == 0
-             || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+#ifdef FUNCTION_ARG_CALLEE_COPIES
+         if (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type), type,
+                                         argpos < n_named_args)
+             /* If it's in a register, we must make a copy of it too.  */
+             /* ??? Is this a sufficient test?  Is there a better one? */
+             && !(TREE_CODE (args[i].tree_value) == VAR_DECL
+                  && REG_P (DECL_RTL (args[i].tree_value))))
            {
-             /* This is a variable-sized object.  Make space on the stack
-                for it.  */
-             rtx size_rtx = expr_size (TREE_VALUE (p));
-
-             if (old_stack_level == 0)
-               {
-                 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
-                 old_pending_adj = pending_stack_adjust;
-                 pending_stack_adjust = 0;
-               }
-
-             copy = gen_rtx (MEM, BLKmode,
-                             allocate_dynamic_stack_space (size_rtx, NULL_RTX,
-                                                           TYPE_ALIGN (type)));
+             args[i].tree_value = build1 (ADDR_EXPR,
+                                          build_pointer_type (type),
+                                          args[i].tree_value);
+             type = build_pointer_type (type);
            }
          else
+#endif
            {
-             int size = int_size_in_bytes (type);
-             copy = assign_stack_temp (TYPE_MODE (type), size, 1);
-           }
+             /* We make a copy of the object and pass the address to the
+                function being called.  */
+             rtx copy;
 
-         store_expr (args[i].tree_value, copy, 0);
+             if (TYPE_SIZE (type) == 0
+                 || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+               {
+                 /* This is a variable-sized object.  Make space on the stack
+                    for it.  */
+                 rtx size_rtx = expr_size (TREE_VALUE (p));
+
+                 if (old_stack_level == 0)
+                   {
+                     emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+                     old_pending_adj = pending_stack_adjust;
+                     pending_stack_adjust = 0;
+                   }
+
+                 copy = gen_rtx (MEM, BLKmode,
+                                 allocate_dynamic_stack_space (size_rtx,
+                                                               NULL_RTX,
+                                                               TYPE_ALIGN (type)));
+               }
+             else
+               {
+                 int size = int_size_in_bytes (type);
+                 copy = assign_stack_temp (TYPE_MODE (type), size, 1);
+               }
+
+             store_expr (args[i].tree_value, copy, 0);
 
-         args[i].tree_value = build1 (ADDR_EXPR, build_pointer_type (type),
-                                      make_tree (type, copy));
-         type = build_pointer_type (type);
+             args[i].tree_value = build1 (ADDR_EXPR,
+                                          build_pointer_type (type),
+                                          make_tree (type, copy));
+             type = build_pointer_type (type);
+           }
        }
-#endif
+#endif /* FUNCTION_ARG_PASS_BY_REFERENCE */
 
       mode = TYPE_MODE (type);
 
@@ -1426,8 +1476,18 @@ expand_call (exp, target, ignore)
 
   /* Get the function to call, in the form of RTL.  */
   if (fndecl)
-    /* Get a SYMBOL_REF rtx for the function address.  */
-    funexp = XEXP (DECL_RTL (fndecl), 0);
+    {
+      /* If this is the first use of the function, see if we need to
+        make an external definition for it.  */
+      if (! TREE_USED (fndecl))
+       {
+         assemble_external (fndecl);
+         TREE_USED (fndecl) = 1;
+       }
+
+      /* Get a SYMBOL_REF rtx for the function address.  */
+      funexp = XEXP (DECL_RTL (fndecl), 0);
+    }
   else
     /* Generate an rtx (probably a pseudo-register) for the address.  */
     {
@@ -1628,7 +1688,7 @@ expand_call (exp, target, ignore)
   /* If register arguments require space on the stack and stack space
      was not preallocated, allocate stack space here for arguments
      passed in registers.  */
-#if ! defined(ALLOCATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)
+#if ! defined(ACCUMULATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)
   if (must_preallocate == 0 && reg_parm_stack_space > 0)
     anti_adjust_stack (GEN_INT (reg_parm_stack_space));
 #endif
@@ -1808,15 +1868,26 @@ expand_call (exp, target, ignore)
     {
       if (target == 0)
        {
-         target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
-                           copy_to_reg (valreg));
-         MEM_IN_STRUCT_P (target)
-           = (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
-              || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
-              || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
-              || TREE_CODE (TREE_TYPE (exp)) == QUAL_UNION_TYPE);
+         /* We used leave the value in the location that it is
+            returned in, but that causes problems if it is used more
+            than once in one expression.  Rather than trying to track
+            when a copy is required, we always copy when TARGET is
+            not specified.  This calling sequence is only used on
+            a few machines and TARGET is usually nonzero.  */
+         if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+           {
+             target = assign_stack_temp (BLKmode,
+                                         int_size_in_bytes (TREE_TYPE (exp)),
+                                         0);
+
+             /* Save this temp slot around the pop below.  */
+             preserve_temp_slots (target);
+           }
+         else
+           target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
        }
-      else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
+
+      if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
        emit_move_insn (target, gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
                                         copy_to_reg (valreg)));
       else
@@ -1988,6 +2059,8 @@ emit_library_call (va_alist)
   int old_inhibit_defer_pop = inhibit_defer_pop;
   int no_queue = 0;
   rtx use_insns;
+  /* library calls are never indirect calls.  */
+  int current_call_is_indirect = 0;
 
   va_start (p);
   orgfun = fun = va_arg (p, rtx);
@@ -2242,6 +2315,8 @@ emit_library_call_value (va_alist)
   rtx use_insns;
   rtx value;
   rtx mem_value = 0;
+  /* library calls are never indirect calls.  */
+  int current_call_is_indirect = 0;
 
   va_start (p);
   orgfun = fun = va_arg (p, rtx);