function.c (assign_parms): Save and restore setting of TREE_USED (parm).
[gcc.git] / gcc / function.c
index e594e7000f58d7b87688383de6a405786821f4e0..1cb8c44bbcd3829d2c47d8cf45eeb56e5268edd7 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -57,6 +57,10 @@ Boston, MA 02111-1307, USA.  */
 #include "obstack.h"
 #include "toplev.h"
 
+#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
+#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
+#endif
+
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
 #endif
@@ -243,10 +247,12 @@ int function_call_count;
 
 tree nonlocal_labels;
 
-/* RTX for stack slot that holds the current handler for nonlocal gotos.
+/* List (chain of EXPR_LIST) of stack slots that hold the current handlers
+   for nonlocal gotos.  There is one for every nonlocal label in the function;
+   this list matches the one in nonlocal_labels.
    Zero when function does not have nonlocal labels.  */
 
-rtx nonlocal_goto_handler_slot;
+rtx nonlocal_goto_handler_slots;
 
 /* RTX for stack slot that holds the stack pointer value to restore
    for a nonlocal goto.
@@ -528,7 +534,7 @@ push_function_context_to (context)
   p->parm_reg_stack_loc = parm_reg_stack_loc;
   p->outgoing_args_size = current_function_outgoing_args_size;
   p->return_rtx = current_function_return_rtx;
-  p->nonlocal_goto_handler_slot = nonlocal_goto_handler_slot;
+  p->nonlocal_goto_handler_slots = nonlocal_goto_handler_slots;
   p->nonlocal_goto_stack_level = nonlocal_goto_stack_level;
   p->nonlocal_labels = nonlocal_labels;
   p->cleanup_label = cleanup_label;
@@ -612,7 +618,7 @@ pop_function_context_from (context)
   parm_reg_stack_loc = p->parm_reg_stack_loc;
   current_function_outgoing_args_size = p->outgoing_args_size;
   current_function_return_rtx = p->return_rtx;
-  nonlocal_goto_handler_slot = p->nonlocal_goto_handler_slot;
+  nonlocal_goto_handler_slots = p->nonlocal_goto_handler_slots;
   nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;
   nonlocal_labels = p->nonlocal_labels;
   cleanup_label = p->cleanup_label;
@@ -669,7 +675,7 @@ void pop_function_context ()
 /* Allocate fixed slots in the stack frame of the current function.  */
 
 /* Return size needed for stack frame based on slots so far allocated.
-   This size counts from zero.  It is not rounded to STACK_BOUNDARY;
+   This size counts from zero.  It is not rounded to PREFERRED_STACK_BOUNDARY;
    the caller may have to do that.  */
 
 HOST_WIDE_INT
@@ -962,6 +968,8 @@ assign_stack_temp (mode, size, keep)
      set from before.  */
   RTX_UNCHANGING_P (p->slot) = 0;
   MEM_IN_STRUCT_P (p->slot) = 0;
+  MEM_SCALAR_P (p->slot) = 0;
+  MEM_ALIAS_SET (p->slot) = 0;
   return p->slot;
 }
 \f
@@ -997,7 +1005,7 @@ assign_temp (type, keep, memory_required, dont_promote)
        size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));
 
       tmp = assign_stack_temp (mode, size, keep);
-      MEM_IN_STRUCT_P (tmp) = AGGREGATE_TYPE_P (type);
+      MEM_SET_IN_STRUCT_P (tmp, AGGREGATE_TYPE_P (type));
       return tmp;
     }
 
@@ -1555,7 +1563,8 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
      previously generated stack slot, then we need to copy the bit in
      case it was set for other reasons.  For instance, it is set for
      __builtin_va_alist.  */
-  MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type) | MEM_IN_STRUCT_P (new);
+  MEM_SET_IN_STRUCT_P (reg,
+                      AGGREGATE_TYPE_P (type) || MEM_IN_STRUCT_P (new));
   MEM_ALIAS_SET (reg) = get_alias_set (type);
 
   /* Now make sure that all refs to the variable, previously made
@@ -2019,8 +2028,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  newmem = gen_rtx_MEM (wanted_mode,
                                        plus_constant (XEXP (tem, 0), offset));
                  RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
-                 MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
-                 MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
+                 MEM_COPY_ATTRIBUTES (newmem, tem);
 
                  /* Make the change and see if the insn remains valid.  */
                  INSN_CODE (insn) = -1;
@@ -2211,8 +2219,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                    newmem = gen_rtx_MEM (wanted_mode,
                                          plus_constant (XEXP (tem, 0), offset));
                    RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
-                   MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
-                   MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
+                   MEM_COPY_ATTRIBUTES (newmem, tem);
 
                    /* Make the change and see if the insn remains valid.  */
                    INSN_CODE (insn) = -1;
@@ -2777,7 +2784,7 @@ gen_mem_addressof (reg, decl)
   PUT_CODE (reg, MEM);
   PUT_MODE (reg, DECL_MODE (decl));
   MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
-  MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
+  MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (type));
   MEM_ALIAS_SET (reg) = get_alias_set (decl);
 
   if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
@@ -2818,6 +2825,10 @@ put_addressof_into_stack (r)
                      TREE_USED (decl) || DECL_INITIAL (decl) != 0);
 }
 
+/* List of replacements made below in purge_addressof_1 when creating
+   bitfield insertions.  */
+static rtx purge_addressof_replacements;
+
 /* Helper function for purge_addressof.  See if the rtx expression at *LOC
    in INSN needs to be changed.  If FORCE, always put any ADDRESSOFs into
    the stack.  */
@@ -2860,7 +2871,7 @@ purge_addressof_1 (loc, insn, force, store)
 
       insns = gen_sequence ();
       end_sequence ();
-      emit_insns_before (insns, insn);
+      emit_insn_before (insns, insn);
       return;
     }
   else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
@@ -2880,6 +2891,50 @@ purge_addressof_1 (loc, insn, force, store)
        {
          int size_x, size_sub;
 
+         if (!insn)
+           {
+             /* When processing REG_NOTES look at the list of
+                replacements done on the insn to find the register that X
+                was replaced by.  */
+             rtx tem;
+
+             for (tem = purge_addressof_replacements; tem != NULL_RTX;
+                  tem = XEXP (XEXP (tem, 1), 1))
+               {
+                 rtx y = XEXP (tem, 0);
+                 if (GET_CODE (y) == MEM
+                     && rtx_equal_p (XEXP (x, 0), XEXP (y, 0)))
+                   {
+                     /* It can happen that the note may speak of things in
+                        a wider (or just different) mode than the code did. 
+                        This is especially true of REG_RETVAL.  */
+
+                     rtx z = XEXP (XEXP (tem, 1), 0);
+                     if (GET_MODE (x) != GET_MODE (y))
+                       {
+                         if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
+                           z = SUBREG_REG (z);
+
+                         /* ??? If we'd gotten into any of the really complex
+                            cases below, I'm not sure we can do a proper
+                            replacement.  Might we be able to delete the
+                            note in some cases?  */
+                         if (GET_MODE_SIZE (GET_MODE (x))
+                             < GET_MODE_SIZE (GET_MODE (y)))
+                           abort ();
+
+                         z = gen_lowpart (GET_MODE (x), z);
+                       }
+
+                     *loc = z;
+                     return;
+                   }
+               }
+
+             /* There should always be such a replacement.  */
+             abort ();
+           }
+
          size_x = GET_MODE_BITSIZE (GET_MODE (x));
          size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
 
@@ -2895,12 +2950,17 @@ purge_addressof_1 (loc, insn, force, store)
 
              if (store)
                {
-                 /* If we can't replace with a register, be afraid.  */
+                 rtx p;
 
                  start_sequence ();
                  val = gen_reg_rtx (GET_MODE (x));
                  if (! validate_change (insn, loc, val, 0))
-                   abort ();
+                   {
+                     /* Discard the current sequence and put the
+                        ADDRESSOF on stack.  */
+                     end_sequence ();
+                     goto give_up;
+                   }
                  seq = gen_sequence ();
                  end_sequence ();
                  emit_insn_before (seq, insn);
@@ -2910,6 +2970,16 @@ purge_addressof_1 (loc, insn, force, store)
                                   val, GET_MODE_SIZE (GET_MODE (sub)),
                                   GET_MODE_SIZE (GET_MODE (sub)));
 
+                 /* Make sure to unshare any shared rtl that store_bit_field
+                    might have created.  */
+                 for (p = get_insns(); p; p = NEXT_INSN (p))
+                   {
+                     reset_used_flags (PATTERN (p));
+                     reset_used_flags (REG_NOTES (p));
+                     reset_used_flags (LOG_LINKS (p));
+                   }
+                 unshare_all_rtl (get_insns ());
+
                  seq = gen_sequence ();
                  end_sequence ();
                  emit_insn_after (seq, insn);
@@ -2922,21 +2992,41 @@ purge_addressof_1 (loc, insn, force, store)
                                           GET_MODE_SIZE (GET_MODE (sub)),
                                           GET_MODE_SIZE (GET_MODE (sub)));
 
-                 /* If we can't replace with a register, be afraid.  */
                  if (! validate_change (insn, loc, val, 0))
-                   abort ();
+                   {
+                     /* Discard the current sequence and put the
+                        ADDRESSOF on stack.  */
+                     end_sequence ();
+                     goto give_up;
+                   }
 
                  seq = gen_sequence ();
                  end_sequence ();
                  emit_insn_before (seq, insn);
                }
 
+             /* Remember the replacement so that the same one can be done
+                on the REG_NOTES.  */
+             purge_addressof_replacements
+               = gen_rtx_EXPR_LIST (VOIDmode, x,
+                                    gen_rtx_EXPR_LIST (VOIDmode, val,
+                                                       purge_addressof_replacements));
+
              /* We replaced with a reg -- all done.  */
              return;
            }
        }
       else if (validate_change (insn, loc, sub, 0))
-       goto restart;
+       {
+         /* Remember the replacement so that the same one can be done
+            on the REG_NOTES.  */
+         purge_addressof_replacements
+           = gen_rtx_EXPR_LIST (VOIDmode, x,
+                                gen_rtx_EXPR_LIST (VOIDmode, sub,
+                                                   purge_addressof_replacements));
+         goto restart;
+       }
+    give_up:;
       /* else give up and put it into the stack */
     }
   else if (code == ADDRESSOF)
@@ -2950,12 +3040,6 @@ purge_addressof_1 (loc, insn, force, store)
       purge_addressof_1 (&SET_SRC (x), insn, force, 0);
       return;
     }
-  else if (code == CALL)
-    {
-      purge_addressof_1 (&XEXP (x, 0), insn, 1, 0);
-      purge_addressof_1 (&XEXP (x, 1), insn, force, 0);
-      return;
-    }
 
   /* Scan all subexpressions. */
   fmt = GET_RTX_FORMAT (code);
@@ -2986,6 +3070,7 @@ purge_addressof (insns)
                           asm_noperands (PATTERN (insn)) > 0, 0);
        purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0);
       }
+  purge_addressof_replacements = 0;
 }
 \f
 /* Pass through the INSNS of function FNDECL and convert virtual register
@@ -3615,13 +3700,22 @@ delete_handlers ()
                TREE_CHAIN (last_t) = TREE_CHAIN (t);
            }
        }
-      if (GET_CODE (insn) == INSN
-         && ((nonlocal_goto_handler_slot != 0
-              && reg_mentioned_p (nonlocal_goto_handler_slot, PATTERN (insn)))
+      if (GET_CODE (insn) == INSN)
+       {
+         int can_delete = 0;
+         rtx t;
+         for (t = nonlocal_goto_handler_slots; t != 0; t = XEXP (t, 1))
+           if (reg_mentioned_p (t, PATTERN (insn)))
+             {
+               can_delete = 1;
+               break;
+             }
+         if (can_delete
              || (nonlocal_goto_stack_level != 0
                  && reg_mentioned_p (nonlocal_goto_stack_level,
-                                     PATTERN (insn)))))
-       delete_insn (insn);
+                                     PATTERN (insn))))
+           delete_insn (insn);
+       }
     }
 }
 
@@ -4021,7 +4115,7 @@ assign_parms (fndecl, second_time)
          /* If this is a memory ref that contains aggregate components,
             mark it as such for cse and loop optimize.  Likewise if it
             is readonly.  */
-         MEM_IN_STRUCT_P (stack_parm) = aggregate;
+         MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
          RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
          MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
        }
@@ -4161,7 +4255,7 @@ assign_parms (fndecl, second_time)
 
          /* If this is a memory ref that contains aggregate components,
             mark it as such for cse and loop optimize.  */
-         MEM_IN_STRUCT_P (stack_parm) = aggregate;
+         MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
        }
 #endif /* 0 */
 
@@ -4218,7 +4312,7 @@ assign_parms (fndecl, second_time)
 
                  /* If this is a memory ref that contains aggregate
                     components, mark it as such for cse and loop optimize.  */
-                 MEM_IN_STRUCT_P (stack_parm) = aggregate;
+                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
                }
 
              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
@@ -4275,7 +4369,7 @@ assign_parms (fndecl, second_time)
            {
              DECL_RTL (parm)
                = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
-             MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
+             MEM_SET_IN_STRUCT_P (DECL_RTL (parm), aggregate);
            }
          else
            DECL_RTL (parm) = parmreg;
@@ -4284,6 +4378,7 @@ assign_parms (fndecl, second_time)
          if (nominal_mode != passed_mode
              || promoted_nominal_mode != promoted_mode)
            {
+             int save_tree_used;
              /* ENTRY_PARM has been converted to PROMOTED_MODE, its
                 mode, by the caller.  We now have to convert it to 
                 NOMINAL_MODE, if different.  However, PARMREG may be in
@@ -4310,8 +4405,11 @@ assign_parms (fndecl, second_time)
              push_to_sequence (conversion_insns);
              tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
 
+             /* TREE_USED gets set erroneously during expand_assignment.  */
+             save_tree_used = TREE_USED (parm);
              expand_assignment (parm,
                                 make_tree (nominal_type, tempreg), 0, 0);
+             TREE_USED (parm) = save_tree_used;
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -4376,7 +4474,7 @@ assign_parms (fndecl, second_time)
              else
                copy = assign_stack_temp (TYPE_MODE (type),
                                          int_size_in_bytes (type), 1);
-             MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type);
+             MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
              RTX_UNCHANGING_P (copy) = TREE_READONLY (parm);
 
              store_expr (parm, copy, 0);
@@ -4531,7 +4629,7 @@ assign_parms (fndecl, second_time)
                                          GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
                  /* If this is a memory ref that contains aggregate components,
                     mark it as such for cse and loop optimize.  */
-                 MEM_IN_STRUCT_P (stack_parm) = aggregate;
+                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
                }
 
              if (promoted_mode != nominal_mode)
@@ -4573,7 +4671,8 @@ assign_parms (fndecl, second_time)
          DECL_RTL (result)
            = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
 
-         MEM_IN_STRUCT_P (DECL_RTL (result)) = AGGREGATE_TYPE_P (restype);
+         MEM_SET_IN_STRUCT_P (DECL_RTL (result), 
+                              AGGREGATE_TYPE_P (restype));
        }
 
       if (TREE_THIS_VOLATILE (parm))
@@ -4600,8 +4699,8 @@ assign_parms (fndecl, second_time)
 #endif
 #endif
 
-#ifdef STACK_BOUNDARY
-#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
+#ifdef PREFERRED_STACK_BOUNDARY
+#define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
 
   current_function_args_size
     = ((current_function_args_size + STACK_BYTES - 1)
@@ -4907,6 +5006,14 @@ uninitialized_vars_warning (block)
          && ! AGGREGATE_TYPE_P (TREE_TYPE (decl))
          && DECL_RTL (decl) != 0
          && GET_CODE (DECL_RTL (decl)) == REG
+         /* Global optimizations can make it difficult to determine if a
+            particular variable has been initialized.  However, a VAR_DECL
+            with a nonzero DECL_INITIAL had an initializer, so do not
+            claim it is potentially uninitialized.
+
+            We do not care about the actual value in DECL_INITIAL, so we do
+            not worry that it may be a dangling pointer.  */
+         && DECL_INITIAL (decl) == NULL_TREE
          && regno_uninitialized (REGNO (DECL_RTL (decl))))
        warning_with_decl (decl,
                           "`%s' might be used uninitialized in this function");
@@ -5395,7 +5502,7 @@ init_function_start (subr, filename, line)
   stack_slot_list = 0;
 
   /* There is no stack slot for handling nonlocal gotos.  */
-  nonlocal_goto_handler_slot = 0;
+  nonlocal_goto_handler_slots = 0;
   nonlocal_goto_stack_level = 0;
 
   /* No labels have been declared for nonlocal use.  */
@@ -5645,8 +5752,10 @@ expand_function_start (subr, parms_have_cleanups)
        {
          DECL_RTL (DECL_RESULT (subr))
            = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
-         MEM_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)))
-           = AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
+         MEM_SET_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)),
+                              AGGREGATE_TYPE_P (TREE_TYPE
+                                                (DECL_RESULT
+                                                 (subr))));
        }
     }
   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
@@ -5915,7 +6024,8 @@ expand_function_end (filename, line, end_bindings)
     }
 
   /* Delete handlers for nonlocal gotos if nothing uses them.  */
-  if (nonlocal_goto_handler_slot != 0 && !current_function_has_nonlocal_label)
+  if (nonlocal_goto_handler_slots != 0
+      && ! current_function_has_nonlocal_label)
     delete_handlers ();
 
   /* End any sequences that failed to be closed due to syntax errors.  */
@@ -6198,9 +6308,9 @@ thread_prologue_and_epilogue_insns (f)
 
       /* Include the new prologue insns in the first block.  Ignore them
         if they form a basic block unto themselves.  */
-      if (basic_block_head && n_basic_blocks
-         && GET_CODE (basic_block_head[0]) != CODE_LABEL)
-       basic_block_head[0] = NEXT_INSN (f);
+      if (x_basic_block_head && n_basic_blocks
+         && GET_CODE (BLOCK_HEAD (0)) != CODE_LABEL)
+       BLOCK_HEAD (0) = NEXT_INSN (f);
 
       /* Retain a map of the prologue insns.  */
       prologue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : head);
@@ -6266,9 +6376,9 @@ thread_prologue_and_epilogue_insns (f)
 
          /* Include the new epilogue insns in the last block.  Ignore
             them if they form a basic block unto themselves.  */
-         if (basic_block_end && n_basic_blocks
-             && GET_CODE (basic_block_end[n_basic_blocks - 1]) != JUMP_INSN)
-           basic_block_end[n_basic_blocks - 1] = tail;
+         if (x_basic_block_end && n_basic_blocks
+             && GET_CODE (BLOCK_END (n_basic_blocks - 1)) != JUMP_INSN)
+           BLOCK_END (n_basic_blocks - 1) = tail;
 
          /* Retain a map of the epilogue insns.  */
          epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
@@ -6328,10 +6438,10 @@ reposition_prologue_and_epilogue_notes (f)
                  if (next)
                    PREV_INSN (next) = prev;
 
-                 /* Whether or not we can depend on basic_block_head
+                 /* Whether or not we can depend on BLOCK_HEAD
                     attempt to keep it up-to-date.  */
-                 if (basic_block_head[0] == note)
-                   basic_block_head[0] = next;
+                 if (BLOCK_HEAD (0) == note)
+                   BLOCK_HEAD (0) = next;
 
                  add_insn_after (note, insn);
                }
@@ -6372,11 +6482,11 @@ reposition_prologue_and_epilogue_notes (f)
                  if (next)
                    PREV_INSN (next) = prev;
 
-                 /* Whether or not we can depend on basic_block_head
+                 /* Whether or not we can depend on BLOCK_HEAD
                     attempt to keep it up-to-date.  */
                  if (n_basic_blocks
-                     && basic_block_head[n_basic_blocks-1] == insn)
-                   basic_block_head[n_basic_blocks-1] = note;
+                     && BLOCK_HEAD (n_basic_blocks-1) == insn)
+                   BLOCK_HEAD (n_basic_blocks-1) = note;
 
                  add_insn_before (note, insn);
                }