OSDN Git Service

* config/cpu/s390/atomicity.h (__exchange_and_add): Add "memory"
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index eb1e14e..9db8ae0 100644 (file)
@@ -1,6 +1,7 @@
 /* Expands front end tree to back end RTL for GCC.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -352,7 +353,7 @@ free_after_compilation (struct function *f)
    This size counts from zero.  It is not rounded to PREFERRED_STACK_BOUNDARY;
    the caller may have to do that.  */
 
-HOST_WIDE_INT
+static HOST_WIDE_INT
 get_func_frame_size (struct function *f)
 {
 #ifdef FRAME_GROWS_DOWNWARD
@@ -1922,8 +1923,9 @@ use_register_for_decl (tree decl)
   if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (decl)))
     return false;
 
-  /* Compiler-generated temporaries can always go in registers.  */
-  if (DECL_ARTIFICIAL (decl))
+  /* If we're not interested in tracking debugging information for
+     this decl, then we can certainly put it in a register.  */
+  if (DECL_IGNORED_P (decl))
     return true;
 
   return (optimize || DECL_REGISTER (decl));
@@ -1990,7 +1992,6 @@ struct assign_parm_data_one
   struct locate_and_pad_arg_data locate;
   int partial;
   BOOL_BITFIELD named_arg : 1;
-  BOOL_BITFIELD last_named : 1;
   BOOL_BITFIELD passed_pointer : 1;
   BOOL_BITFIELD on_stack : 1;
   BOOL_BITFIELD loaded_in_reg : 1;
@@ -2105,6 +2106,7 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
       decl = build_decl (PARM_DECL, NULL_TREE, type);
       DECL_ARG_TYPE (decl) = type;
       DECL_ARTIFICIAL (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
 
       TREE_CHAIN (decl) = fnargs;
       fnargs = decl;
@@ -2133,24 +2135,15 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
 
   memset (data, 0, sizeof (*data));
 
-  /* Set LAST_NAMED if this is last named arg before last anonymous args.  */
-  if (current_function_stdarg)
-    {
-      tree tem;
-      for (tem = TREE_CHAIN (parm); tem; tem = TREE_CHAIN (tem))
-       if (DECL_NAME (tem))
-         break;
-      if (tem == 0)
-       data->last_named = true;
-    }
-
-  /* Set NAMED_ARG if this arg should be treated as a named arg.  For
-     most machines, if this is a varargs/stdarg function, then we treat
-     the last named arg as if it were anonymous too.  */
-  if (targetm.calls.strict_argument_naming (&all->args_so_far))
-    data->named_arg = 1;
+  /* NAMED_ARG is a mis-nomer.  We really mean 'non-varadic'. */
+  if (!current_function_stdarg)
+    data->named_arg = 1;  /* No varadic parms.  */
+  else if (TREE_CHAIN (parm))
+    data->named_arg = 1;  /* Not the last non-varadic parm. */
+  else if (targetm.calls.strict_argument_naming (&all->args_so_far))
+    data->named_arg = 1;  /* Only varadic ones are unnamed.  */
   else
-    data->named_arg = !data->last_named;
+    data->named_arg = 0;  /* Treat as varadic.  */
 
   nominal_type = TREE_TYPE (parm);
   passed_type = DECL_ARG_TYPE (parm);
@@ -2403,22 +2396,21 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
 
   set_mem_attributes (stack_parm, parm, 1);
 
-  boundary = FUNCTION_ARG_BOUNDARY (data->promoted_mode, data->passed_type);
-  align = 0;
+  boundary = data->locate.boundary;
+  align = BITS_PER_UNIT;
 
   /* If we're padding upward, we know that the alignment of the slot
      is FUNCTION_ARG_BOUNDARY.  If we're using slot_offset, we're
      intentionally forcing upward padding.  Otherwise we have to come
      up with a guess at the alignment based on OFFSET_RTX.  */
-  if (data->locate.where_pad == upward || data->entry_parm)
+  if (data->locate.where_pad != downward || data->entry_parm)
     align = boundary;
   else if (GET_CODE (offset_rtx) == CONST_INT)
     {
       align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
       align = align & -align;
     }
-  if (align > 0)
-    set_mem_align (stack_parm, align);
+  set_mem_align (stack_parm, align);
 
   if (data->entry_parm)
     set_reg_attrs_for_parm (data->entry_parm, stack_parm);
@@ -2490,7 +2482,6 @@ assign_parm_adjust_entry_rtl (struct assign_parm_data_one *data)
 /* A subroutine of assign_parms.  Adjust DATA->STACK_RTL such that it's
    always valid and properly aligned.  */
 
-
 static void
 assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
 {
@@ -2499,8 +2490,12 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
   /* If we can't trust the parm stack slot to be aligned enough for its
      ultimate type, don't use that slot after entry.  We'll make another
      stack slot, if we need one.  */
-  if (STRICT_ALIGNMENT && stack_parm
-      && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm))
+  if (stack_parm
+      && ((STRICT_ALIGNMENT
+          && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm))
+         || (data->nominal_type
+             && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm)
+             && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY)))
     stack_parm = NULL;
 
   /* If parm was passed in memory, and we need to convert it on entry,
@@ -2546,6 +2541,9 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
 {
   rtx entry_parm = data->entry_parm;
   rtx stack_parm = data->stack_parm;
+  HOST_WIDE_INT size;
+  HOST_WIDE_INT size_stored;
+  rtx orig_entry_parm = entry_parm;
 
   if (GET_CODE (entry_parm) == PARALLEL)
     entry_parm = emit_group_move_into_temps (entry_parm);
@@ -2553,68 +2551,78 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
   /* If we've a non-block object that's nevertheless passed in parts,
      reconstitute it in register operations rather than on the stack.  */
   if (GET_CODE (entry_parm) == PARALLEL
-      && data->nominal_mode != BLKmode
-      && XVECLEN (entry_parm, 0) > 1
-      && use_register_for_decl (parm))
+      && data->nominal_mode != BLKmode)
     {
-      rtx parmreg = gen_reg_rtx (data->nominal_mode);
+      rtx elt0 = XEXP (XVECEXP (orig_entry_parm, 0, 0), 0);
 
-      push_to_sequence (all->conversion_insns);
+      if ((XVECLEN (entry_parm, 0) > 1
+          || hard_regno_nregs[REGNO (elt0)][GET_MODE (elt0)] > 1)
+         && use_register_for_decl (parm))
+       {
+         rtx parmreg = gen_reg_rtx (data->nominal_mode);
 
-      /* For values returned in multiple registers, handle possible
-        incompatible calls to emit_group_store.
+         push_to_sequence (all->conversion_insns);
 
-        For example, the following would be invalid, and would have to
-        be fixed by the conditional below:
+         /* For values returned in multiple registers, handle possible
+            incompatible calls to emit_group_store.
 
-          emit_group_store ((reg:SF), (parallel:DF))
-          emit_group_store ((reg:SI), (parallel:DI))
+            For example, the following would be invalid, and would have to
+            be fixed by the conditional below:
 
-        An example of this are doubles in e500 v2:
-          (parallel:DF (expr_list (reg:SI) (const_int 0))
-                       (expr_list (reg:SI) (const_int 4))).  */
-      if (data->nominal_mode != data->passed_mode)
-       {
-         rtx t = gen_reg_rtx (GET_MODE (entry_parm));
-         emit_group_store (t, entry_parm, NULL_TREE,
-                           GET_MODE_SIZE (GET_MODE (entry_parm)));
-         convert_move (parmreg, t, 0);
-       }
-      else
-       emit_group_store (parmreg, entry_parm, data->nominal_type,
-                         int_size_in_bytes (data->nominal_type));
+            emit_group_store ((reg:SF), (parallel:DF))
+            emit_group_store ((reg:SI), (parallel:DI))
 
-      all->conversion_insns = get_insns ();
-      end_sequence ();
+            An example of this are doubles in e500 v2:
+            (parallel:DF (expr_list (reg:SI) (const_int 0))
+            (expr_list (reg:SI) (const_int 4))).  */
+         if (data->nominal_mode != data->passed_mode)
+           {
+             rtx t = gen_reg_rtx (GET_MODE (entry_parm));
+             emit_group_store (t, entry_parm, NULL_TREE,
+                               GET_MODE_SIZE (GET_MODE (entry_parm)));
+             convert_move (parmreg, t, 0);
+           }
+         else
+           emit_group_store (parmreg, entry_parm, data->nominal_type,
+                             int_size_in_bytes (data->nominal_type));
 
-      SET_DECL_RTL (parm, parmreg);
-      return;
+         all->conversion_insns = get_insns ();
+         end_sequence ();
+
+         SET_DECL_RTL (parm, parmreg);
+         return;
+       }
+    }
+
+  size = int_size_in_bytes (data->passed_type);
+  size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
+  if (stack_parm == 0)
+    {
+      DECL_ALIGN (parm) = MAX (DECL_ALIGN (parm), BITS_PER_WORD);
+      stack_parm = assign_stack_local (BLKmode, size_stored,
+                                      DECL_ALIGN (parm));
+      if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size)
+       PUT_MODE (stack_parm, GET_MODE (entry_parm));
+      set_mem_attributes (stack_parm, parm, 1);
     }
 
   /* If a BLKmode arrives in registers, copy it to a stack slot.  Handle
      calls that pass values in multiple non-contiguous locations.  */
   if (REG_P (entry_parm) || GET_CODE (entry_parm) == PARALLEL)
     {
-      HOST_WIDE_INT size = int_size_in_bytes (data->passed_type);
-      HOST_WIDE_INT size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
       rtx mem;
 
       /* Note that we will be storing an integral number of words.
         So we have to be careful to ensure that we allocate an
-        integral number of words.  We do this below in the
+        integral number of words.  We do this above when we call
         assign_stack_local if space was not allocated in the argument
         list.  If it was, this will not work if PARM_BOUNDARY is not
         a multiple of BITS_PER_WORD.  It isn't clear how to fix this
         if it becomes a problem.  Exception is when BLKmode arrives
         with arguments not conforming to word_mode.  */
 
-      if (stack_parm == 0)
-       {
-         stack_parm = assign_stack_local (BLKmode, size_stored, 0);
-         data->stack_parm = stack_parm;
-         PUT_MODE (stack_parm, GET_MODE (entry_parm));
-         set_mem_attributes (stack_parm, parm, 1);
-       }
+      if (data->stack_parm == 0)
+       ;
       else if (GET_CODE (entry_parm) == PARALLEL)
        ;
       else
@@ -2684,7 +2692,16 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
        move_block_from_reg (REGNO (entry_parm), mem,
                             size_stored / UNITS_PER_WORD);
     }
+  else if (data->stack_parm == 0)
+    {
+      push_to_sequence (all->conversion_insns);
+      emit_block_move (stack_parm, data->entry_parm, GEN_INT (size),
+                      BLOCK_OP_NORMAL);
+      all->conversion_insns = get_insns ();
+      end_sequence ();
+    }
 
+  data->stack_parm = stack_parm;
   SET_DECL_RTL (parm, stack_parm);
 }
 
@@ -2885,6 +2902,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 {
   /* Value must be stored in the stack slot STACK_PARM during function
      execution.  */
+  bool to_conversion = false;
 
   if (data->promoted_mode != data->nominal_mode)
     {
@@ -2894,6 +2912,8 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
       emit_move_insn (tempreg, validize_mem (data->entry_parm));
 
       push_to_sequence (all->conversion_insns);
+      to_conversion = true;
+
       data->entry_parm = convert_to_mode (data->nominal_mode, tempreg,
                                          TYPE_UNSIGNED (TREE_TYPE (parm)));
 
@@ -2901,33 +2921,43 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
        /* ??? This may need a big-endian conversion on sparc64.  */
        data->stack_parm
          = adjust_address (data->stack_parm, data->nominal_mode, 0);
-
-      all->conversion_insns = get_insns ();
-      end_sequence ();
     }
 
   if (data->entry_parm != data->stack_parm)
     {
+      rtx src, dest;
+
       if (data->stack_parm == 0)
        {
          data->stack_parm
            = assign_stack_local (GET_MODE (data->entry_parm),
                                  GET_MODE_SIZE (GET_MODE (data->entry_parm)),
-                                 0);
+                                 TYPE_ALIGN (data->passed_type));
          set_mem_attributes (data->stack_parm, parm, 1);
        }
 
-      if (data->promoted_mode != data->nominal_mode)
+      dest = validize_mem (data->stack_parm);
+      src = validize_mem (data->entry_parm);
+
+      if (MEM_P (src))
        {
-         push_to_sequence (all->conversion_insns);
-         emit_move_insn (validize_mem (data->stack_parm),
-                         validize_mem (data->entry_parm));
-         all->conversion_insns = get_insns ();
-         end_sequence ();
+         /* Use a block move to handle potentially misaligned entry_parm.  */
+         if (!to_conversion)
+           push_to_sequence (all->conversion_insns);
+         to_conversion = true;
+
+         emit_block_move (dest, src,
+                          GEN_INT (int_size_in_bytes (data->passed_type)),
+                          BLOCK_OP_NORMAL);
        }
       else
-       emit_move_insn (validize_mem (data->stack_parm),
-                       validize_mem (data->entry_parm));
+       emit_move_insn (dest, src);
+    }
+
+  if (to_conversion)
+    {
+      all->conversion_insns = get_insns ();
+      end_sequence ();
     }
 
   SET_DECL_RTL (parm, data->stack_parm);
@@ -2965,7 +2995,8 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all, tree fnargs)
 
              /* split_complex_arg put the real and imag parts in
                 pseudos.  Move them to memory.  */
-             tmp = assign_stack_local (DECL_MODE (parm), size, 0);
+             tmp = assign_stack_local (DECL_MODE (parm), size,
+                                       TYPE_ALIGN (TREE_TYPE (parm)));
              set_mem_attributes (tmp, parm, 1);
              rmem = adjust_address_nv (tmp, inner, 0);
              imem = adjust_address_nv (tmp, inner, GET_MODE_SIZE (inner));
@@ -3014,7 +3045,6 @@ assign_parms (tree fndecl)
   struct assign_parm_data_all all;
   tree fnargs, parm;
   rtx internal_arg_pointer;
-  int varargs_setup = 0;
 
   /* If the reg that the virtual arg pointer will be translated into is
      not a fixed reg or is the stack pointer, make a copy of the virtual
@@ -3049,16 +3079,8 @@ assign_parms (tree fndecl)
          continue;
        }
 
-      /* Handle stdargs.  LAST_NAMED is a slight mis-nomer; it's also true
-        for the unnamed dummy argument following the last named argument.
-        See ABI silliness wrt strict_argument_naming and NAMED_ARG.  So
-        we only want to do this when we get to the actual last named
-        argument, which will be the first time LAST_NAMED gets set.  */
-      if (data.last_named && !varargs_setup)
-       {
-         varargs_setup = true;
-         assign_parms_setup_varargs (&all, &data, false);
-       }
+      if (current_function_stdarg && !TREE_CHAIN (parm))
+       assign_parms_setup_varargs (&all, &data, false);
 
       /* Find out where the parameter arrives in this function.  */
       assign_parm_find_entry_rtl (&all, &data);
@@ -3409,6 +3431,7 @@ locate_and_pad_parm (enum machine_mode passed_mode, tree type, int in_regs,
   where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
   boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
   locate->where_pad = where_pad;
+  locate->boundary = boundary;
 
 #ifdef ARGS_GROW_DOWNWARD
   locate->slot_offset.constant = -initial_offset_ptr->constant;
@@ -4418,18 +4441,6 @@ expand_function_end (void)
   if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
     sjlj_emit_function_exit_after (get_last_insn ());
 
-  /* If we had calls to alloca, and this machine needs
-     an accurate stack pointer to exit the function,
-     insert some code to save and restore the stack pointer.  */
-  if (! EXIT_IGNORE_STACK
-      && current_function_calls_alloca)
-    {
-      rtx tem = 0;
-
-      emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
-      emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
-    }
-
   /* If scalar return value was computed in a pseudo-reg, or was a named
      return value that got dumped to the stack, copy that to the hard
      return register.  */
@@ -4557,6 +4568,18 @@ expand_function_end (void)
   /* Output the label for the naked return from the function.  */
   emit_label (naked_return_label);
 
+  /* If we had calls to alloca, and this machine needs
+     an accurate stack pointer to exit the function,
+     insert some code to save and restore the stack pointer.  */
+  if (! EXIT_IGNORE_STACK
+      && current_function_calls_alloca)
+    {
+      rtx tem = 0;
+
+      emit_stack_save (SAVE_FUNCTION, &tem, parm_birth_insn);
+      emit_stack_restore (SAVE_FUNCTION, tem, NULL_RTX);
+    }
+
   /* ??? This should no longer be necessary since stupid is no longer with
      us, but there are some parts of the compiler (eg reload_combine, and
      sh mach_dep_reorg) that still try and compute their own lifetime info
@@ -4588,7 +4611,7 @@ get_arg_pointer_save_area (struct function *f)
       end_sequence ();
 
       push_topmost_sequence ();
-      emit_insn_after (seq, get_insns ());
+      emit_insn_after (seq, entry_of_function ());
       pop_topmost_sequence ();
     }
 
@@ -5107,9 +5130,9 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
       /* Can't deal with multiple successors of the entry block
          at the moment.  Function should always have at least one
          entry point.  */
-      gcc_assert (EDGE_COUNT (ENTRY_BLOCK_PTR->succs) == 1);
+      gcc_assert (single_succ_p (ENTRY_BLOCK_PTR));
 
-      insert_insn_on_edge (seq, EDGE_SUCC (ENTRY_BLOCK_PTR, 0));
+      insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
       inserted = 1;
     }
 #endif
@@ -5205,7 +5228,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
                  /* If this block has only one successor, it both jumps
                     and falls through to the fallthru block, so we can't
                     delete the edge.  */
-                 if (EDGE_COUNT (bb->succs) == 1)
+                 if (single_succ_p (bb))
                    {
                      ei_next (&ei2);
                      continue;
@@ -5227,7 +5250,7 @@ thread_prologue_and_epilogue_insns (rtx f ATTRIBUTE_UNUSED)
          emit_barrier_after (BB_END (last));
          emit_return_into_block (last, epilogue_line_note);
          epilogue_end = BB_END (last);
-         EDGE_SUCC (last, 0)->flags &= ~EDGE_FALLTHRU;
+         single_succ_edge (last)->flags &= ~EDGE_FALLTHRU;
          goto epilogue_done;
        }
     }
@@ -5302,8 +5325,6 @@ epilogue_done:
     {
       basic_block bb = e->src;
       rtx insn = BB_END (bb);
-      rtx i;
-      rtx newinsn;
 
       if (!CALL_P (insn)
          || ! SIBLING_CALL_P (insn))
@@ -5323,8 +5344,7 @@ epilogue_done:
       record_insns (seq, &sibcall_epilogue);
       set_insn_locators (seq, epilogue_locator);
 
-      i = PREV_INSN (insn);
-      newinsn = emit_insn_before (seq, insn);
+      emit_insn_before (seq, insn);
       ei_next (&ei);
     }
 #endif