OSDN Git Service

* config/usegld.h: New file.
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index d92ca59..a8574d2 100644 (file)
@@ -705,7 +705,8 @@ vt_stack_adjustments (void)
 static rtx cfa_base_rtx;
 static HOST_WIDE_INT cfa_base_offset;
 
-/* Compute a CFA-based value for the stack pointer.  */
+/* Compute a CFA-based value for an ADJUSTMENT made to stack_pointer_rtx
+   or hard_frame_pointer_rtx.  */
 
 static inline rtx
 compute_cfa_pointer (HOST_WIDE_INT adjustment)
@@ -745,6 +746,10 @@ use_narrower_mode_test (rtx *loc, void *data)
     case REG:
       if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
        return 1;
+      if (!validate_subreg (GET_MODE (subreg), GET_MODE (*loc),
+                           *loc, subreg_lowpart_offset (GET_MODE (subreg),
+                                                        GET_MODE (*loc))))
+       return 1;
       return -1;
     case PLUS:
     case MINUS:
@@ -3117,8 +3122,8 @@ canonicalize_values_mark (void **slot, void *data)
            decl_or_value odv = dv_from_value (node->loc);
            void **oslot = shared_hash_find_slot_noinsert (set->vars, odv);
 
-           oslot = set_slot_part (set, val, oslot, odv, 0,
-                                  node->init, NULL_RTX);
+           set_slot_part (set, val, oslot, odv, 0,
+                          node->init, NULL_RTX);
 
            VALUE_RECURSED_INTO (node->loc) = true;
          }
@@ -3329,8 +3334,8 @@ canonicalize_values_star (void **slot, void *data)
       }
 
   if (val)
-    cslot = set_slot_part (set, val, cslot, cdv, 0,
-                          VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
+    set_slot_part (set, val, cslot, cdv, 0,
+                  VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
 
   slot = clobber_slot_part (set, cval, slot, 0, NULL);
 
@@ -3401,7 +3406,7 @@ canonicalize_vars_star (void **slot, void *data)
 
   slot = set_slot_part (set, cval, slot, dv, 0,
                        node->init, node->set_src);
-  slot = clobber_slot_part (set, cval, slot, 0, node->set_src);
+  clobber_slot_part (set, cval, slot, 0, node->set_src);
 
   return 1;
 }
@@ -4113,8 +4118,9 @@ find_mem_expr_in_1pdv (tree expr, rtx val, htab_t vars)
   VALUE_RECURSED_INTO (val) = true;
 
   for (node = var->var_part[0].loc_chain; node; node = node->next)
-    if (MEM_P (node->loc) && MEM_EXPR (node->loc) == expr
-       && MEM_OFFSET (node->loc) == 0)
+    if (MEM_P (node->loc)
+       && MEM_EXPR (node->loc) == expr
+       && INT_MEM_OFFSET (node->loc) == 0)
       {
        where = node;
        break;
@@ -4177,11 +4183,10 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
        {
          for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
            {
-             /* We want to remove dying MEMs that doesn't refer to
-                DECL.  */
+             /* We want to remove dying MEMs that doesn't refer to DECL.  */
              if (GET_CODE (loc->loc) == MEM
                  && (MEM_EXPR (loc->loc) != decl
-                     || MEM_OFFSET (loc->loc))
+                     || INT_MEM_OFFSET (loc->loc) != 0)
                  && !mem_dies_at_call (loc->loc))
                break;
              /* We want to move here MEMs that do refer to DECL.  */
@@ -4225,7 +4230,7 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
 
          if (GET_CODE (loc->loc) != MEM
              || (MEM_EXPR (loc->loc) == decl
-                 && MEM_OFFSET (loc->loc) == 0)
+                 && INT_MEM_OFFSET (loc->loc) == 0)
              || !mem_dies_at_call (loc->loc))
            {
              if (old_loc != loc->loc && emit_notes)
@@ -4832,7 +4837,7 @@ get_address_mode (rtx mem)
 static rtx
 replace_expr_with_values (rtx loc)
 {
-  if (REG_P (loc))
+  if (REG_P (loc) || GET_CODE (loc) == ENTRY_VALUE)
     return NULL;
   else if (MEM_P (loc))
     {
@@ -5047,6 +5052,7 @@ add_uses (rtx *ploc, void *data)
          if (MEM_P (vloc)
              && !REG_P (XEXP (vloc, 0))
              && !MEM_P (XEXP (vloc, 0))
+             && GET_CODE (XEXP (vloc, 0)) != ENTRY_VALUE
              && (GET_CODE (XEXP (vloc, 0)) != PLUS
                  || XEXP (XEXP (vloc, 0), 0) != cfa_base_rtx
                  || !CONST_INT_P (XEXP (XEXP (vloc, 0), 1))))
@@ -5125,6 +5131,7 @@ add_uses (rtx *ploc, void *data)
          if (MEM_P (oloc)
              && !REG_P (XEXP (oloc, 0))
              && !MEM_P (XEXP (oloc, 0))
+             && GET_CODE (XEXP (oloc, 0)) != ENTRY_VALUE
              && (GET_CODE (XEXP (oloc, 0)) != PLUS
                  || XEXP (XEXP (oloc, 0), 0) != cfa_base_rtx
                  || !CONST_INT_P (XEXP (XEXP (oloc, 0), 1))))
@@ -5210,6 +5217,8 @@ add_uses_1 (rtx *x, void *cui)
   for_each_rtx (x, add_uses, cui);
 }
 
+#define EXPR_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
+
 /* Attempt to reverse the EXPR operation in the debug info.  Say for
    reg1 = reg2 + 6 even when reg2 is no longer live we
    can express its value as VAL - 6.  */
@@ -5376,6 +5385,7 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
       if (MEM_P (loc) && type == MO_VAL_SET
          && !REG_P (XEXP (loc, 0))
          && !MEM_P (XEXP (loc, 0))
+         && GET_CODE (XEXP (loc, 0)) != ENTRY_VALUE
          && (GET_CODE (XEXP (loc, 0)) != PLUS
              || XEXP (XEXP (loc, 0), 0) != cfa_base_rtx
              || !CONST_INT_P (XEXP (XEXP (loc, 0), 1))))
@@ -5579,9 +5589,11 @@ prepare_call_arguments (basic_block bb, rtx insn)
   rtx this_arg = NULL_RTX;
   tree type = NULL_TREE, t, fndecl = NULL_TREE;
   tree obj_type_ref = NULL_TREE;
-  CUMULATIVE_ARGS args_so_far;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
 
-  memset (&args_so_far, 0, sizeof (args_so_far));
+  memset (&args_so_far_v, 0, sizeof (args_so_far_v));
+  args_so_far = pack_cumulative_args (&args_so_far_v);
   if (GET_CODE (call) == PARALLEL)
     call = XVECEXP (call, 0, 0);
   if (GET_CODE (call) == SET)
@@ -5629,11 +5641,11 @@ prepare_call_arguments (basic_block bb, rtx insn)
                  tree struct_addr = build_pointer_type (TREE_TYPE (type));
                  enum machine_mode mode = TYPE_MODE (struct_addr);
                  rtx reg;
-                 INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX, fndecl,
+                 INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
                                        nargs + 1);
-                 reg = targetm.calls.function_arg (&args_so_far, mode,
+                 reg = targetm.calls.function_arg (args_so_far, mode,
                                                    struct_addr, true);
-                 targetm.calls.function_arg_advance (&args_so_far, mode,
+                 targetm.calls.function_arg_advance (args_so_far, mode,
                                                      struct_addr, true);
                  if (reg == NULL_RTX)
                    {
@@ -5646,16 +5658,16 @@ prepare_call_arguments (basic_block bb, rtx insn)
                          }
                    }
                }
-#endif
              else
-               INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX, fndecl,
+#endif
+               INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
                                      nargs);
              if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
                {
                  enum machine_mode mode;
                  t = TYPE_ARG_TYPES (type);
                  mode = TYPE_MODE (TREE_VALUE (t));
-                 this_arg = targetm.calls.function_arg (&args_so_far, mode,
+                 this_arg = targetm.calls.function_arg (args_so_far, mode,
                                                         TREE_VALUE (t), true);
                  if (this_arg && !REG_P (this_arg))
                    this_arg = NULL_RTX;
@@ -5735,12 +5747,12 @@ prepare_call_arguments (basic_block bb, rtx insn)
            tree argtype = TREE_VALUE (t);
            enum machine_mode mode = TYPE_MODE (argtype);
            rtx reg;
-           if (pass_by_reference (&args_so_far, mode, argtype, true))
+           if (pass_by_reference (&args_so_far_v, mode, argtype, true))
              {
                argtype = build_pointer_type (argtype);
                mode = TYPE_MODE (argtype);
              }
-           reg = targetm.calls.function_arg (&args_so_far, mode,
+           reg = targetm.calls.function_arg (args_so_far, mode,
                                              argtype, true);
            if (TREE_CODE (argtype) == REFERENCE_TYPE
                && INTEGRAL_TYPE_P (TREE_TYPE (argtype))
@@ -5794,7 +5806,7 @@ prepare_call_arguments (basic_block bb, rtx insn)
                        }
                  }
              }
-           targetm.calls.function_arg_advance (&args_so_far, mode,
+           targetm.calls.function_arg_advance (args_so_far, mode,
                                                argtype, true);
            t = TREE_CHAIN (t);
          }
@@ -7038,7 +7050,7 @@ set_variable_part (dataflow_set *set, rtx loc,
       if (!slot)
        slot = shared_hash_find_slot_unshare (&set->vars, dv, iopt);
     }
-  slot = set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
+  set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
 }
 
 /* Remove all recorded register locations for the given variable part
@@ -7119,7 +7131,7 @@ clobber_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
   if (!slot)
     return;
 
-  slot = clobber_slot_part (set, loc, slot, offset, set_src);
+  clobber_slot_part (set, loc, slot, offset, set_src);
 }
 
 /* Delete the part of variable's location from dataflow set SET.  The
@@ -7218,7 +7230,7 @@ delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
   if (!slot)
     return;
 
-  slot = delete_slot_part (set, loc, slot, offset);
+  delete_slot_part (set, loc, slot, offset);
 }
 
 /* Structure for passing some other parameters to function
@@ -7411,7 +7423,7 @@ vt_expand_loc (rtx loc, htab_t vars, bool ignore_cur_loc)
   data.dummy = false;
   data.cur_loc_changed = false;
   data.ignore_cur_loc = ignore_cur_loc;
-  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
+  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
                                    vt_expand_loc_callback, &data);
 
   if (loc && MEM_P (loc))
@@ -7433,7 +7445,7 @@ vt_expand_loc_dummy (rtx loc, htab_t vars, bool *pcur_loc_changed)
   data.dummy = true;
   data.cur_loc_changed = false;
   data.ignore_cur_loc = false;
-  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
+  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
                                          vt_expand_loc_callback, &data);
   *pcur_loc_changed = data.cur_loc_changed;
   return ret;
@@ -8371,6 +8383,39 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
   return false;
 }
 
+/* Helper function for vt_add_function_parameter.  RTL is
+   the expression and VAL corresponding cselib_val pointer
+   for which ENTRY_VALUE should be created.  */
+
+static void
+create_entry_value (rtx rtl, cselib_val *val)
+{
+  cselib_val *val2;
+  struct elt_loc_list *el;
+  el = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el));
+  el->next = val->locs;
+  el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (rtl));
+  ENTRY_VALUE_EXP (el->loc) = rtl;
+  el->setting_insn = get_insns ();
+  val->locs = el;
+  val2 = cselib_lookup_from_insn (el->loc, GET_MODE (rtl), true,
+                                 VOIDmode, get_insns ());
+  if (val2
+      && val2 != val
+      && val2->locs
+      && rtx_equal_p (val2->locs->loc, el->loc))
+    {
+      struct elt_loc_list *el2;
+
+      preserve_value (val2);
+      el2 = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el2));
+      el2->next = val2->locs;
+      el2->loc = val->val_rtx;
+      el2->setting_insn = get_insns ();
+      val2->locs = el2;
+    }
+}
+
 /* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK.  */
 
 static void
@@ -8393,6 +8438,28 @@ vt_add_function_parameter (tree parm)
   if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
     return;
 
+  /* If there is a DRAP register, rewrite the incoming location of parameters
+     passed on the stack into MEMs based on the argument pointer, as the DRAP
+     register can be reused for other purposes and we do not track locations
+     based on generic registers.  But the prerequisite is that this argument
+     pointer be also the virtual CFA pointer, see vt_initialize.  */
+  if (MEM_P (incoming)
+      && stack_realign_drap
+      && arg_pointer_rtx == cfa_base_rtx
+      && (XEXP (incoming, 0) == crtl->args.internal_arg_pointer
+         || (GET_CODE (XEXP (incoming, 0)) == PLUS
+             && XEXP (XEXP (incoming, 0), 0)
+                == crtl->args.internal_arg_pointer
+             && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
+    {
+      HOST_WIDE_INT off = -FIRST_PARM_OFFSET (current_function_decl);
+      if (GET_CODE (XEXP (incoming, 0)) == PLUS)
+       off += INTVAL (XEXP (XEXP (incoming, 0), 1));
+      incoming
+       = replace_equiv_address_nv (incoming,
+                                   plus_constant (arg_pointer_rtx, off));
+    }
+
   if (!vt_get_decl_and_offset (incoming, &decl, &offset))
     {
       if (REG_P (incoming) || MEM_P (incoming))
@@ -8473,14 +8540,7 @@ vt_add_function_parameter (tree parm)
       if (dv_is_value_p (dv))
        {
          cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
-         struct elt_loc_list *el;
-         el = (struct elt_loc_list *)
-           ggc_alloc_cleared_atomic (sizeof (*el));
-         el->next = val->locs;
-         el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
-         ENTRY_VALUE_EXP (el->loc) = incoming;
-         el->setting_insn = get_insns ();
-         val->locs = el;
+         create_entry_value (incoming, val);
          if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
              && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
            {
@@ -8492,13 +8552,7 @@ vt_add_function_parameter (tree parm)
              if (val)
                {
                  preserve_value (val);
-                 el = (struct elt_loc_list *)
-                   ggc_alloc_cleared_atomic (sizeof (*el));
-                 el->next = val->locs;
-                 el->loc = gen_rtx_ENTRY_VALUE (indmode);
-                 ENTRY_VALUE_EXP (el->loc) = mem;
-                 el->setting_insn = get_insns ();
-                 val->locs = el;
+                 create_entry_value (mem, val);
                }
            }
        }
@@ -8607,9 +8661,11 @@ vt_init_cfa_base (void)
 
   /* Tell alias analysis that cfa_base_rtx should share
      find_base_term value with stack pointer or hard frame pointer.  */
-  vt_equate_reg_base_value (cfa_base_rtx,
-                           frame_pointer_needed
-                           ? hard_frame_pointer_rtx : stack_pointer_rtx);
+  if (!frame_pointer_needed)
+    vt_equate_reg_base_value (cfa_base_rtx, stack_pointer_rtx);
+  else if (!crtl->stack_realign_tried)
+    vt_equate_reg_base_value (cfa_base_rtx, hard_frame_pointer_rtx);
+
   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
                                 VOIDmode, get_insns ());
   preserve_value (val);
@@ -8625,7 +8681,7 @@ vt_init_cfa_base (void)
 static bool
 vt_initialize (void)
 {
-  basic_block bb, prologue_bb = NULL;
+  basic_block bb, prologue_bb = single_succ (ENTRY_BLOCK_PTR);
   HOST_WIDE_INT fp_cfa_offset = -1;
 
   alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
@@ -8683,6 +8739,16 @@ vt_initialize (void)
 
   CLEAR_HARD_REG_SET (argument_reg_set);
 
+  /* In order to factor out the adjustments made to the stack pointer or to
+     the hard frame pointer and thus be able to use DW_OP_fbreg operations
+     instead of individual location lists, we're going to rewrite MEMs based
+     on them into MEMs based on the CFA by de-eliminating stack_pointer_rtx
+     or hard_frame_pointer_rtx to the virtual CFA pointer frame_pointer_rtx
+     resp. arg_pointer_rtx.  We can do this either when there is no frame
+     pointer in the function and stack adjustments are consistent for all
+     basic blocks or when there is a frame pointer and no stack realignment.
+     But we first have to check that frame_pointer_rtx resp. arg_pointer_rtx
+     has been eliminated.  */
   if (!frame_pointer_needed)
     {
       rtx reg, elim;
@@ -8725,10 +8791,38 @@ vt_initialize (void)
            }
          if (elim != hard_frame_pointer_rtx)
            fp_cfa_offset = -1;
-         else
-           prologue_bb = single_succ (ENTRY_BLOCK_PTR);
+       }
+      else
+       fp_cfa_offset = -1;
+    }
+
+  /* If the stack is realigned and a DRAP register is used, we're going to
+     rewrite MEMs based on it representing incoming locations of parameters
+     passed on the stack into MEMs based on the argument pointer.  Although
+     we aren't going to rewrite other MEMs, we still need to initialize the
+     virtual CFA pointer in order to ensure that the argument pointer will
+     be seen as a constant throughout the function.
+
+     ??? This doesn't work if FRAME_POINTER_CFA_OFFSET is defined.  */
+  else if (stack_realign_drap)
+    {
+      rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+      reg = frame_pointer_rtx;
+#else
+      reg = arg_pointer_rtx;
+#endif
+      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+      if (elim != reg)
+       {
+         if (GET_CODE (elim) == PLUS)
+           elim = XEXP (elim, 0);
+         if (elim == hard_frame_pointer_rtx)
+           vt_init_cfa_base ();
        }
     }
+
   if (frame_pointer_needed)
     {
       rtx insn;
@@ -8829,6 +8923,7 @@ vt_initialize (void)
                    }
 
                  if (bb == prologue_bb
+                     && fp_cfa_offset != -1
                      && hard_frame_pointer_adjustment == -1
                      && RTX_FRAME_RELATED_P (insn)
                      && fp_setter (insn))
@@ -9018,7 +9113,7 @@ variable_tracking_main (void)
 static bool
 gate_handle_var_tracking (void)
 {
-  return (flag_var_tracking);
+  return (flag_var_tracking && !targetm.delay_vartrack);
 }
 
 
@@ -9038,6 +9133,6 @@ struct rtl_opt_pass pass_variable_tracking =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
+  TODO_verify_rtl_sharing               /* todo_flags_finish */
  }
 };