OSDN Git Service

fix for see
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index 83bfdb1..704d2f5 100644 (file)
 #include "hashtab.h"
 #include "regs.h"
 #include "expr.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 /* Type of micro operation.  */
 enum micro_operation_type
@@ -138,7 +140,11 @@ typedef struct micro_operation_def
     HOST_WIDE_INT adjust;
   } u;
 
-  /* The instruction which the micro operation is in.  */
+  /* The instruction which the micro operation is in, for MO_USE,
+     MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
+     instruction or note in the original flow (before any var-tracking
+     notes are inserted, to simplify emission of notes), for MO_SET
+     and MO_CLOBBER.  */
   rtx insn;
 } micro_operation;
 
@@ -266,19 +272,12 @@ static htab_t changed_variables;
 /* Shall notes be emitted?  */
 static bool emit_notes;
 
-/* Fake variable for stack pointer.  */
-tree frame_base_decl;
-
-/* Stack adjust caused by function prologue.  */
-static HOST_WIDE_INT frame_stack_adjust;
-
 /* Local function prototypes.  */
 static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
                                          HOST_WIDE_INT *);
 static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
                                               HOST_WIDE_INT *);
 static void bb_stack_adjust_offset (basic_block);
-static HOST_WIDE_INT prologue_stack_adjust (void);
 static bool vt_stack_adjustments (void);
 static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
 static hashval_t variable_htab_hash (const void *);
@@ -296,9 +295,11 @@ static void vars_clear (htab_t);
 static variable unshare_variable (dataflow_set *set, variable var);
 static int vars_copy_1 (void **, void *);
 static void vars_copy (htab_t, htab_t);
+static void var_reg_set (dataflow_set *, rtx);
 static void var_reg_delete_and_set (dataflow_set *, rtx);
 static void var_reg_delete (dataflow_set *, rtx);
 static void var_regno_delete (dataflow_set *, int);
+static void var_mem_set (dataflow_set *, rtx);
 static void var_mem_delete_and_set (dataflow_set *, rtx);
 static void var_mem_delete (dataflow_set *, rtx);
 
@@ -333,7 +334,6 @@ static void dump_dataflow_set (dataflow_set *);
 static void dump_dataflow_sets (void);
 
 static void variable_was_changed (variable, htab_t);
-static void set_frame_base_location (dataflow_set *, rtx);
 static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
 static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
 static int emit_note_insn_var_location (void **, void *);
@@ -489,41 +489,9 @@ bb_stack_adjust_offset (basic_block bb)
   VTI (bb)->out.stack_adjust = offset;
 }
 
-/* Compute stack adjustment caused by function prologue.  */
-
-static HOST_WIDE_INT
-prologue_stack_adjust (void)
-{
-  HOST_WIDE_INT offset = 0;
-  basic_block bb = ENTRY_BLOCK_PTR->next_bb;
-  rtx insn;
-  rtx end;
-
-  if (!BB_END (bb))
-    return 0;
-
-  end = NEXT_INSN (BB_END (bb));
-  for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
-    {
-      if (NOTE_P (insn)
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
-       break;
-
-      if (INSN_P (insn))
-       {
-         HOST_WIDE_INT tmp;
-
-         insn_stack_adjust_offset_pre_post (insn, &tmp, &tmp);
-         offset += tmp;
-       }
-    }
-
-  return offset;
-}
-
 /* Compute stack adjustments for all blocks by traversing DFS tree.
    Return true when the adjustments on all incoming edges are consistent.
-   Heavily borrowed from flow_depth_first_order_compute.  */
+   Heavily borrowed from pre_and_rev_post_order_compute.  */
 
 static bool
 vt_stack_adjustments (void)
@@ -533,10 +501,10 @@ vt_stack_adjustments (void)
 
   /* Initialize entry block.  */
   VTI (ENTRY_BLOCK_PTR)->visited = true;
-  VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = frame_stack_adjust;
+  VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
 
   /* Allocate stack for back-tracking up CFG.  */
-  stack = xmalloc ((n_basic_blocks + 1) * sizeof (edge_iterator));
+  stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
   sp = 0;
 
   /* Push the first edge on to the stack.  */
@@ -587,27 +555,28 @@ vt_stack_adjustments (void)
   return true;
 }
 
-/* Adjust stack reference MEM by ADJUSTMENT bytes and return the new rtx.  */
+/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
+   to the argument pointer.  Return the new rtx.  */
 
 static rtx
 adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
 {
-  rtx adjusted_mem;
-  rtx tmp;
+  rtx addr, cfa, tmp;
 
-  if (adjustment == 0)
-    return mem;
+#ifdef FRAME_POINTER_CFA_OFFSET
+  adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
+  cfa = plus_constant (frame_pointer_rtx, adjustment);
+#else
+  adjustment -= ARG_POINTER_CFA_OFFSET (current_function_decl);
+  cfa = plus_constant (arg_pointer_rtx, adjustment);
+#endif
 
-  adjusted_mem = copy_rtx (mem);
-  XEXP (adjusted_mem, 0) = replace_rtx (XEXP (adjusted_mem, 0),
-                                       stack_pointer_rtx,
-                                       gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                                                     GEN_INT (adjustment)));
-  tmp = simplify_rtx (XEXP (adjusted_mem, 0));
+  addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
+  tmp = simplify_rtx (addr);
   if (tmp)
-    XEXP (adjusted_mem, 0) = tmp;
+    addr = tmp;
 
-  return adjusted_mem;
+  return replace_equiv_address_nv (mem, addr);
 }
 
 /* The hash function for variable_htab, computes the hash value
@@ -829,6 +798,19 @@ vars_copy (htab_t dst, htab_t src)
   htab_traverse (src, vars_copy_1, dst);
 }
 
+/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
+
+static void
+var_reg_set (dataflow_set *set, rtx loc)
+{
+  tree decl = REG_EXPR (loc);
+  HOST_WIDE_INT offset = REG_OFFSET (loc);
+
+  if (set->regs[REGNO (loc)] == NULL)
+    attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
+  set_variable_part (set, loc, decl, offset);
+}
+
 /* Delete current content of register LOC in dataflow set SET
    and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
 
@@ -856,9 +838,7 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc)
          nextp = &node->next;
        }
     }
-  if (set->regs[REGNO (loc)] == NULL)
-    attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
-  set_variable_part (set, loc, decl, offset);
+  var_reg_set (set, loc);
 }
 
 /* Delete current content of register LOC in dataflow set SET.  */
@@ -895,12 +875,12 @@ var_regno_delete (dataflow_set *set, int regno)
   *reg = NULL;
 }
 
-/* Delete and set the location part of variable MEM_EXPR (LOC)
-   in dataflow set SET to LOC.
+/* Set the location part of variable MEM_EXPR (LOC) in dataflow set
+   SET to LOC.
    Adjust the address first if it is stack pointer based.  */
 
 static void
-var_mem_delete_and_set (dataflow_set *set, rtx loc)
+var_mem_set (dataflow_set *set, rtx loc)
 {
   tree decl = MEM_EXPR (loc);
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
@@ -908,6 +888,16 @@ var_mem_delete_and_set (dataflow_set *set, rtx loc)
   set_variable_part (set, loc, decl, offset);
 }
 
+/* Delete and set the location part of variable MEM_EXPR (LOC)
+   in dataflow set SET to LOC.
+   Adjust the address first if it is stack pointer based.  */
+
+static void
+var_mem_delete_and_set (dataflow_set *set, rtx loc)
+{
+  var_mem_set (set, loc);
+}
+
 /* Delete the location part LOC from dataflow set SET.
    Adjust the address first if it is stack pointer based.  */
 
@@ -1107,7 +1097,7 @@ variable_union (void **slot, void *data)
          dst_l = 0;
          for (node = dst->var_part[j].loc_chain; node; node = node->next)
            dst_l++;
-         vui = xcalloc (src_l + dst_l, sizeof (struct variable_union_info));
+         vui = XCNEWVEC (struct variable_union_info, src_l + dst_l);
 
          /* Fill in the locations from DST.  */
          for (node = dst->var_part[j].loc_chain, jj = 0; node;
@@ -1584,7 +1574,7 @@ add_stores (rtx loc, rtx expr, void *insn)
                   && track_expr_p (REG_EXPR (loc)))
                  ? MO_SET : MO_CLOBBER);
       mo->u.loc = loc;
-      mo->insn = (rtx) insn;
+      mo->insn = NEXT_INSN ((rtx) insn);
     }
   else if (MEM_P (loc)
           && MEM_EXPR (loc)
@@ -1595,7 +1585,7 @@ add_stores (rtx loc, rtx expr, void *insn)
 
       mo->type = GET_CODE (expr) == CLOBBER ? MO_CLOBBER : MO_SET;
       mo->u.loc = loc;
-      mo->insn = (rtx) insn;
+      mo->insn = NEXT_INSN ((rtx) insn);
     }
 }
 
@@ -1626,6 +1616,16 @@ compute_bb_dataflow (basic_block bb)
            break;
 
          case MO_USE:
+           {
+             rtx loc = VTI (bb)->mos[i].u.loc;
+
+             if (GET_CODE (loc) == REG)
+               var_reg_set (out, loc);
+             else if (GET_CODE (loc) == MEM)
+               var_mem_set (out, loc);
+           }
+           break;
+
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
@@ -1650,14 +1650,7 @@ compute_bb_dataflow (basic_block bb)
            break;
 
          case MO_ADJUST:
-           {
-             rtx base;
-
-             out->stack_adjust += VTI (bb)->mos[i].u.adjust;
-             base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
-                                                       out->stack_adjust));
-             set_frame_base_location (out, base);
-           }
+           out->stack_adjust += VTI (bb)->mos[i].u.adjust;
            break;
        }
     }
@@ -1682,10 +1675,10 @@ vt_find_locations (void)
 
   /* Compute reverse completion order of depth first search of the CFG
      so that the data-flow runs faster.  */
-  rc_order = xmalloc (n_basic_blocks * sizeof (int));
-  bb_order = xmalloc (last_basic_block * sizeof (int));
-  flow_depth_first_order_compute (NULL, rc_order);
-  for (i = 0; i < n_basic_blocks; i++)
+  rc_order = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS);
+  bb_order = XNEWVEC (int, last_basic_block);
+  pre_and_rev_post_order_compute (NULL, rc_order, false);
+  for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
     bb_order[rc_order[i]] = i;
   free (rc_order);
 
@@ -1780,8 +1773,7 @@ dump_attrs_list (attrs list)
   for (; list; list = list->next)
     {
       print_mem_expr (dump_file, list->decl);
-      fprintf (dump_file, "+");
-      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, list->offset);
+      fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
     }
   fprintf (dump_file, "\n");
 }
@@ -1831,9 +1823,8 @@ dump_dataflow_set (dataflow_set *set)
 {
   int i;
 
-  fprintf (dump_file, "Stack adjustment: ");
-  fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, set->stack_adjust);
-  fprintf (dump_file, "\n");
+  fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
+          set->stack_adjust);
   for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
     {
       if (set->regs[i])
@@ -1912,31 +1903,6 @@ variable_was_changed (variable var, htab_t htab)
     }
 }
 
-/* Set the location of frame_base_decl to LOC in dataflow set SET.  This
-   function expects that frame_base_decl has already one location for offset 0
-   in the variable table.  */
-
-static void
-set_frame_base_location (dataflow_set *set, rtx loc)
-{
-  variable var;
-  
-  var = htab_find_with_hash (set->vars, frame_base_decl,
-                            VARIABLE_HASH_VAL (frame_base_decl));
-  gcc_assert (var);
-  gcc_assert (var->n_var_parts == 1);
-  gcc_assert (!var->var_part[0].offset);
-  gcc_assert (var->var_part[0].loc_chain);
-
-  /* If frame_base_decl is shared unshare it first.  */
-  if (var->refcount > 1)
-    var = unshare_variable (set, var);
-
-  var->var_part[0].loc_chain->loc = loc;
-  var->var_part[0].cur_loc = loc;
-  variable_was_changed (var, set->vars);
-}
-
 /* Set the part of variable's location in the dataflow set SET.  The variable
    part is specified by variable's declaration DECL and offset OFFSET and the
    part's location by LOC.  */
@@ -2427,6 +2393,18 @@ emit_notes_in_bb (basic_block bb)
            break;
 
          case MO_USE:
+           {
+             rtx loc = VTI (bb)->mos[i].u.loc;
+
+             if (GET_CODE (loc) == REG)
+               var_reg_set (&set, loc);
+             else
+               var_mem_set (&set, loc);
+
+             emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+           }
+           break;
+
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
@@ -2436,10 +2414,7 @@ emit_notes_in_bb (basic_block bb)
              else
                var_mem_delete_and_set (&set, loc);
 
-             if (VTI (bb)->mos[i].type == MO_USE)
-               emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
-             else
-               emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
            }
            break;
 
@@ -2454,22 +2429,14 @@ emit_notes_in_bb (basic_block bb)
                var_mem_delete (&set, loc);
 
              if (VTI (bb)->mos[i].type == MO_USE_NO_VAR)
-               emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
-             else
                emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+             else
+               emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
            }
            break;
 
          case MO_ADJUST:
-           {
-             rtx base;
-
-             set.stack_adjust += VTI (bb)->mos[i].u.adjust;
-             base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
-                                                       set.stack_adjust));
-             set_frame_base_location (&set, base);
-             emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
-           }
+           set.stack_adjust += VTI (bb)->mos[i].u.adjust;
            break;
        }
     }
@@ -2573,7 +2540,6 @@ vt_add_function_parameters (void)
 
       gcc_assert (parm == decl);
 
-      incoming = eliminate_regs (incoming, 0, NULL_RTX);
       out = &VTI (ENTRY_BLOCK_PTR)->out;
 
       if (REG_P (incoming))
@@ -2584,9 +2550,7 @@ vt_add_function_parameters (void)
          set_variable_part (out, incoming, parm, offset);
        }
       else if (MEM_P (incoming))
-       {
-         set_variable_part (out, incoming, parm, offset);
-       }
+       set_variable_part (out, incoming, parm, offset);
     }
 }
 
@@ -2603,7 +2567,7 @@ vt_initialize (void)
   FOR_EACH_BB (bb)
     {
       rtx insn;
-      HOST_WIDE_INT pre, post;
+      HOST_WIDE_INT pre, post = 0;
 
       /* Count the number of micro operations.  */
       VTI (bb)->n_mos = 0;
@@ -2628,8 +2592,7 @@ vt_initialize (void)
        }
 
       /* Add the micro-operations to the array.  */
-      VTI (bb)->mos = xmalloc (VTI (bb)->n_mos
-                              * sizeof (struct micro_operation_def));
+      VTI (bb)->mos = XNEWVEC (micro_operation, VTI (bb)->n_mos);
       VTI (bb)->n_mos = 0;
       for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
           insn = NEXT_INSN (insn))
@@ -2681,15 +2644,18 @@ vt_initialize (void)
                }
 
              n1 = VTI (bb)->n_mos;
+             /* This will record NEXT_INSN (insn), such that we can
+                insert notes before it without worrying about any
+                notes that MO_USEs might emit after the insn.  */
              note_stores (PATTERN (insn), add_stores, insn);
              n2 = VTI (bb)->n_mos - 1;
 
-             /* Order the MO_SETs to be before MO_CLOBBERs.  */
+             /* Order the MO_CLOBBERs to be before MO_SETs.  */
              while (n1 < n2)
                {
-                 while (n1 < n2 && VTI (bb)->mos[n1].type == MO_SET)
+                 while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
                    n1++;
-                 while (n1 < n2 && VTI (bb)->mos[n2].type == MO_CLOBBER)
+                 while (n1 < n2 && VTI (bb)->mos[n2].type == MO_SET)
                    n2--;
                  if (n1 < n2)
                    {
@@ -2731,28 +2697,6 @@ vt_initialize (void)
   changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
                                   NULL);
   vt_add_function_parameters ();
-
-  if (!frame_pointer_needed)
-    {
-      rtx base;
-
-      /* Create fake variable for tracking stack pointer changes.  */
-      frame_base_decl = make_node (VAR_DECL);
-      DECL_NAME (frame_base_decl) = get_identifier ("___frame_base_decl");
-      TREE_TYPE (frame_base_decl) = char_type_node;
-      DECL_ARTIFICIAL (frame_base_decl) = 1;
-      DECL_IGNORED_P (frame_base_decl) = 1;
-
-      /* Set its initial "location".  */
-      frame_stack_adjust = -prologue_stack_adjust ();
-      base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
-                                               frame_stack_adjust));
-      set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
-    }
-  else
-    {
-      frame_base_decl = NULL;
-    }
 }
 
 /* Free the data structures needed for variable tracking.  */
@@ -2781,11 +2725,11 @@ vt_finalize (void)
 
 /* The entry point to variable tracking pass.  */
 
-void
+unsigned int
 variable_tracking_main (void)
 {
   if (n_basic_blocks > 500 && n_edges / n_basic_blocks >= 20)
-    return;
+    return 0;
 
   mark_dfs_back_edges ();
   vt_initialize ();
@@ -2794,18 +2738,45 @@ variable_tracking_main (void)
       if (!vt_stack_adjustments ())
        {
          vt_finalize ();
-         return;
+         return 0;
        }
     }
 
   vt_find_locations ();
   vt_emit_notes ();
 
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
       dump_dataflow_sets ();
-      dump_flow_info (dump_file);
+      dump_flow_info (dump_file, dump_flags);
     }
 
   vt_finalize ();
+  return 0;
+}
+\f
+static bool
+gate_handle_var_tracking (void)
+{
+  return (flag_var_tracking);
 }
+
+
+
+struct tree_opt_pass pass_variable_tracking =
+{
+  "vartrack",                           /* name */
+  gate_handle_var_tracking,             /* gate */
+  variable_tracking_main,               /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_VAR_TRACKING,                      /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'V'                                   /* letter */
+};
+