]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/calls.c
*** empty log message ***
[gcc.git] / gcc / calls.c
index 02f60ca867cbdd2a685e83e8ede098255c1ea1c3..310bc4a558530cec21e3641e9640b4604226b8e5 100644 (file)
@@ -1208,22 +1208,11 @@ expand_call (exp, target, ignore)
               highest_outgoing_arg_in_use - initial_highest_arg_in_use);
       needed = 0;
 
-      /* The only way the stack pointer can change here is if some arguments
-        which are passed in memory are constructed in place in the outgoing
-        argument area.  All objects which are constructed in place have
-        pass_on_stack == 1 (see store_one_arg ()).
-
-        The test for arguments being constructed on the stack is just an
-        optimization: it would be correct but suboptimal to call
-        copy_addr_to_reg () unconditionally.  */
+      /* The address of the outgoing argument list must not be copied to a
+        register here, because argblock would be left pointing to the
+        wrong place after the call to allocate_dynamic_stack_space below. */
 
       argblock = virtual_outgoing_args_rtx;
-      for (i = 0; i < num_actuals; i++)
-       if (args[i].pass_on_stack)
-         {
-           argblock = copy_addr_to_reg (argblock);
-           break;
-         }
 
 #else /* not ACCUMULATE_OUTGOING_ARGS */
       if (inhibit_defer_pop == 0)
@@ -1258,6 +1247,47 @@ expand_call (exp, target, ignore)
 #endif /* not ACCUMULATE_OUTGOING_ARGS */
     }
 
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+  /* The save/restore code in store_one_arg handles all cases except one:
+     a constructor call (including a C function returning a BLKmode struct)
+     to initialize an argument.  */
+  if (stack_arg_under_construction)
+    {
+#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+      rtx push_size = gen_rtx (CONST_INT, VOIDmode,
+                              reg_parm_stack_space + args_size.constant);
+#else
+      rtx push_size = gen_rtx (CONST_INT, VOIDmode, args_size.constant);
+#endif
+      if (old_stack_level == 0)
+       {
+         emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
+         old_pending_adj = pending_stack_adjust;
+         pending_stack_adjust = 0;
+         /* stack_arg_under_construction says whether a stack arg is
+            being constructed at the old stack level.  Pushing the stack
+            gets a clean outgoing argument block.  */
+         old_stack_arg_under_construction = stack_arg_under_construction;
+         stack_arg_under_construction = 0;
+         /* Make a new map for the new argument list.  */
+         stack_usage_map = (char *)alloca (highest_outgoing_arg_in_use);
+         bzero (stack_usage_map, highest_outgoing_arg_in_use);
+         highest_outgoing_arg_in_use = 0;
+       }
+      allocate_dynamic_stack_space (push_size, 0, BITS_PER_UNIT);
+    }
+  /* If argument evaluation might modify the stack pointer, copy the
+     address of the argument list to a register.  */
+  for (i = 0; i < num_actuals; i++)
+    if (args[i].pass_on_stack)
+      {
+       argblock = copy_addr_to_reg (argblock);
+       break;
+      }
+#endif
+
+
   /* If we preallocated stack space, compute the address of each argument.
      We need not ensure it is a valid memory address here; it will be 
      validized when it is used.  */
@@ -1310,37 +1340,6 @@ expand_call (exp, target, ignore)
 #endif
 #endif
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-  /* The save/restore code in store_one_arg handles all cases except one:
-     a constructor call (including a C function returning a BLKmode struct)
-     to initialize an argument.  */
-  if (stack_arg_under_construction)
-    {
-#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
-      rtx push_size = gen_rtx (CONST_INT, VOIDmode,
-                              reg_parm_stack_space + args_size.constant);
-#else
-      rtx push_size = gen_rtx (CONST_INT, VOIDmode, args_size.constant);
-#endif
-      if (old_stack_level == 0)
-       {
-         emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
-         old_pending_adj = pending_stack_adjust;
-         pending_stack_adjust = 0;
-         /* stack_arg_under_construction says whether a stack arg is
-            being constructed at the old stack level.  Pushing the stack
-            gets a clean outgoing argument block.  */
-         old_stack_arg_under_construction = stack_arg_under_construction;
-         stack_arg_under_construction = 0;
-         /* Make a new map for the new argument list.  */
-         stack_usage_map = (char *)alloca (highest_outgoing_arg_in_use);
-         bzero (stack_usage_map, highest_outgoing_arg_in_use);
-         highest_outgoing_arg_in_use = 0;
-       }
-      allocate_dynamic_stack_space (push_size, 0, BITS_PER_UNIT);
-    }
-#endif
-
   /* Don't try to defer pops if preallocating, not even from the first arg,
      since ARGBLOCK probably refers to the SP.  */
   if (argblock)
This page took 0.028475 seconds and 5 git commands to generate.