OSDN Git Service

PR c++/39786
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index a24755f..5cc8ced 100644 (file)
@@ -723,12 +723,25 @@ static inline bool
 dv_is_decl_p (decl_or_value dv)
 {
   if (!dv)
-    return false;
+    return true;
 
-  if (GET_CODE ((rtx)dv) == VALUE)
-    return false;
+  /* Make sure relevant codes don't overlap.  */
+  switch ((int)TREE_CODE ((tree)dv))
+    {
+    case (int)VAR_DECL:
+    case (int)PARM_DECL:
+    case (int)RESULT_DECL:
+    case (int)FUNCTION_DECL:
+    case (int)DEBUG_EXPR_DECL:
+    case (int)COMPONENT_REF:
+      return true;
 
-  return true;
+    case (int)VALUE:
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
 }
 
 /* Return true if a decl_or_value is a VALUE rtl.  */
@@ -790,21 +803,13 @@ dv_pool (decl_or_value dv)
   return dv_onepart_p (dv) ? valvar_pool : var_pool;
 }
 
-#define IS_DECL_CODE(C) ((C) == VAR_DECL || (C) == PARM_DECL \
-                        || (C) == RESULT_DECL || (C) == COMPONENT_REF)
-
-/* Check that VALUE won't ever look like a DECL.  */
-static char check_value_is_not_decl [(!IS_DECL_CODE ((enum tree_code)VALUE))
-                                    ? 1 : -1] ATTRIBUTE_UNUSED;
-
-
 /* Build a decl_or_value out of a decl.  */
 static inline decl_or_value
 dv_from_decl (tree decl)
 {
   decl_or_value dv;
-  gcc_assert (!decl || IS_DECL_CODE (TREE_CODE (decl)));
   dv = decl;
+  gcc_assert (dv_is_decl_p (dv));
   return dv;
 }
 
@@ -813,8 +818,8 @@ static inline decl_or_value
 dv_from_value (rtx value)
 {
   decl_or_value dv;
-  gcc_assert (value);
   dv = value;
+  gcc_assert (dv_is_value_p (dv));
   return dv;
 }
 
@@ -2218,7 +2223,7 @@ dataflow_set_union (dataflow_set *dst, dataflow_set *src)
 
 /* Whether the value is currently being expanded.  */
 #define VALUE_RECURSED_INTO(x) \
-  (RTL_FLAG_CHECK1 ("VALUE_RECURSED_INTO", (x), VALUE)->used)
+  (RTL_FLAG_CHECK2 ("VALUE_RECURSED_INTO", (x), VALUE, DEBUG_EXPR)->used)
 /* Whether the value is in changed_variables hash table.  */
 #define VALUE_CHANGED(x) \
   (RTL_FLAG_CHECK1 ("VALUE_CHANGED", (x), VALUE)->frame_related)
@@ -4108,6 +4113,9 @@ track_expr_p (tree expr, bool need_rtl)
   rtx decl_rtl;
   tree realdecl;
 
+  if (TREE_CODE (expr) == DEBUG_EXPR_DECL)
+    return DECL_RTL_SET_P (expr);
+
   /* If EXPR is not a parameter or a variable do not track it.  */
   if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL)
     return 0;
@@ -4351,7 +4359,9 @@ replace_expr_with_values (rtx loc)
     return NULL;
   else if (MEM_P (loc))
     {
-      cselib_val *addr = cselib_lookup (XEXP (loc, 0), Pmode, 0);
+      enum machine_mode address_mode
+       = targetm.addr_space.address_mode (MEM_ADDR_SPACE (loc));
+      cselib_val *addr = cselib_lookup (XEXP (loc, 0), address_mode, 0);
       if (addr)
        return replace_equiv_address_nv (loc, addr->val_rtx);
       else
@@ -4485,7 +4495,9 @@ count_uses (rtx *loc, void *cuip)
          if (MEM_P (*loc)
              && !REG_P (XEXP (*loc, 0)) && !MEM_P (XEXP (*loc, 0)))
            {
-             val = cselib_lookup (XEXP (*loc, 0), Pmode, false);
+             enum machine_mode address_mode
+               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (*loc));
+             val = cselib_lookup (XEXP (*loc, 0), address_mode, false);
 
              if (val && !cselib_preserved_value_p (val))
                {
@@ -4605,7 +4617,10 @@ add_uses (rtx *loc, void *data)
              && !REG_P (XEXP (vloc, 0)) && !MEM_P (XEXP (vloc, 0)))
            {
              rtx mloc = vloc;
-             cselib_val *val = cselib_lookup (XEXP (mloc, 0), Pmode, 0);
+             enum machine_mode address_mode
+               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+             cselib_val *val
+               = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
              if (val && !cselib_preserved_value_p (val))
                {
@@ -4616,7 +4631,8 @@ add_uses (rtx *loc, void *data)
                  cselib_preserve_value (val);
                  mo->type = MO_VAL_USE;
                  mloc = cselib_subst_to_values (XEXP (mloc, 0));
-                 mo->u.loc = gen_rtx_CONCAT (Pmode, val->val_rtx, mloc);
+                 mo->u.loc = gen_rtx_CONCAT (address_mode,
+                                             val->val_rtx, mloc);
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    log_op_type (mo->u.loc, cui->bb, cui->insn,
                                 mo->type, dump_file);
@@ -4672,7 +4688,10 @@ add_uses (rtx *loc, void *data)
              && !REG_P (XEXP (oloc, 0)) && !MEM_P (XEXP (oloc, 0)))
            {
              rtx mloc = oloc;
-             cselib_val *val = cselib_lookup (XEXP (mloc, 0), Pmode, 0);
+             enum machine_mode address_mode
+               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+             cselib_val *val
+               = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
              if (val && !cselib_preserved_value_p (val))
                {
@@ -4683,7 +4702,8 @@ add_uses (rtx *loc, void *data)
                  cselib_preserve_value (val);
                  mo->type = MO_VAL_USE;
                  mloc = cselib_subst_to_values (XEXP (mloc, 0));
-                 mo->u.loc = gen_rtx_CONCAT (Pmode, val->val_rtx, mloc);
+                 mo->u.loc = gen_rtx_CONCAT (address_mode,
+                                             val->val_rtx, mloc);
                  mo->insn = cui->insn;
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    log_op_type (mo->u.loc, cui->bb, cui->insn,
@@ -4816,14 +4836,16 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
          && !REG_P (XEXP (loc, 0)) && !MEM_P (XEXP (loc, 0)))
        {
          rtx mloc = loc;
-         cselib_val *val = cselib_lookup (XEXP (mloc, 0), Pmode, 0);
+         enum machine_mode address_mode
+           = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+         cselib_val *val = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
          if (val && !cselib_preserved_value_p (val))
            {
              cselib_preserve_value (val);
              mo->type = MO_VAL_USE;
              mloc = cselib_subst_to_values (XEXP (mloc, 0));
-             mo->u.loc = gen_rtx_CONCAT (Pmode, val->val_rtx, mloc);
+             mo->u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
              mo->insn = cui->insn;
              if (dump_file && (dump_flags & TDF_DETAILS))
                log_op_type (mo->u.loc, cui->bb, cui->insn,
@@ -4973,8 +4995,8 @@ add_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
   note_uses (&PATTERN (insn), add_uses_1, &cui);
   n2 = VTI (bb)->n_mos - 1;
 
-  /* Order the MO_USEs to be before MO_USE_NO_VARs,
-     MO_VAL_LOC and MO_VAL_USE.  */
+  /* Order the MO_USEs to be before MO_USE_NO_VARs and MO_VAL_USE, and
+     MO_VAL_LOC last.  */
   while (n1 < n2)
     {
       while (n1 < n2 && VTI (bb)->mos[n1].type == MO_USE)
@@ -4991,6 +5013,24 @@ add_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
        }
     }
 
+  n2 = VTI (bb)->n_mos - 1;
+
+  while (n1 < n2)
+    {
+      while (n1 < n2 && VTI (bb)->mos[n1].type != MO_VAL_LOC)
+       n1++;
+      while (n1 < n2 && VTI (bb)->mos[n2].type == MO_VAL_LOC)
+       n2--;
+      if (n1 < n2)
+       {
+         micro_operation sw;
+
+         sw = VTI (bb)->mos[n1];
+         VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
+         VTI (bb)->mos[n2] = sw;
+       }
+    }
+
   if (CALL_P (insn))
     {
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
@@ -6220,26 +6260,9 @@ delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
   slot = delete_slot_part (set, loc, slot, offset);
 }
 
-/* Wrap result in CONST:MODE if needed to preserve the mode.  */
-
-static rtx
-check_wrap_constant (enum machine_mode mode, rtx result)
-{
-  if (!result || GET_MODE (result) == mode)
-    return result;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "  wrapping result in const to preserve mode %s\n",
-            GET_MODE_NAME (mode));
-
-  result = wrap_constant (mode, result);
-  gcc_assert (GET_MODE (result) == mode);
-
-  return result;
-}
-
 /* Callback for cselib_expand_value, that looks for expressions
-   holding the value in the var-tracking hash tables.  */
+   holding the value in the var-tracking hash tables.  Return X for
+   standard processing, anything else is to be used as-is.  */
 
 static rtx
 vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
@@ -6248,21 +6271,58 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
   decl_or_value dv;
   variable var;
   location_chain loc;
-  rtx result;
+  rtx result, subreg, xret;
+
+  switch (GET_CODE (x))
+    {
+    case SUBREG:
+      subreg = SUBREG_REG (x);
+
+      if (GET_CODE (SUBREG_REG (x)) != VALUE)
+       return x;
+
+      subreg = cselib_expand_value_rtx_cb (SUBREG_REG (x), regs,
+                                          max_depth - 1,
+                                          vt_expand_loc_callback, data);
+
+      if (!subreg)
+       return NULL;
+
+      result = simplify_gen_subreg (GET_MODE (x), subreg,
+                                   GET_MODE (SUBREG_REG (x)),
+                                   SUBREG_BYTE (x));
+
+      /* Invalid SUBREGs are ok in debug info.  ??? We could try
+        alternate expansions for the VALUE as well.  */
+      if (!result && (REG_P (subreg) || MEM_P (subreg)))
+       result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
+
+      return result;
+
+    case DEBUG_EXPR:
+      dv = dv_from_decl (DEBUG_EXPR_TREE_DECL (x));
+      xret = NULL;
+      break;
 
-  gcc_assert (GET_CODE (x) == VALUE);
+    case VALUE:
+      dv = dv_from_value (x);
+      xret = x;
+      break;
+
+    default:
+      return x;
+    }
 
   if (VALUE_RECURSED_INTO (x))
     return NULL;
 
-  dv = dv_from_value (x);
   var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
 
   if (!var)
-    return NULL;
+    return xret;
 
   if (var->n_var_parts == 0)
-    return NULL;
+    return xret;
 
   gcc_assert (var->n_var_parts == 1);
 
@@ -6273,13 +6333,15 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
     {
       result = cselib_expand_value_rtx_cb (loc->loc, regs, max_depth,
                                           vt_expand_loc_callback, vars);
-      result = check_wrap_constant (GET_MODE (loc->loc), result);
       if (result)
        break;
     }
 
   VALUE_RECURSED_INTO (x) = false;
-  return result;
+  if (result)
+    return result;
+  else
+    return xret;
 }
 
 /* Expand VALUEs in LOC, using VARS as well as cselib's equivalence
@@ -6288,14 +6350,11 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
 static rtx
 vt_expand_loc (rtx loc, htab_t vars)
 {
-  rtx newloc;
-
   if (!MAY_HAVE_DEBUG_INSNS)
     return loc;
 
-  newloc = cselib_expand_value_rtx_cb (loc, scratch_regs, 5,
-                                      vt_expand_loc_callback, vars);
-  loc = check_wrap_constant (GET_MODE (loc), newloc);
+  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 5,
+                                   vt_expand_loc_callback, vars);
 
   if (loc && MEM_P (loc))
     loc = targetm.delegitimize_address (loc);
@@ -6329,6 +6388,9 @@ emit_note_insn_var_location (void **varp, void *data)
 
   decl = dv_as_decl (var->dv);
 
+  if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
+    goto clear;
+
   gcc_assert (decl);
 
   complete = true;
@@ -6354,7 +6416,7 @@ emit_note_insn_var_location (void **varp, void *data)
          continue;
        }
       loc[n_var_parts] = loc2;
-      mode = GET_MODE (loc[n_var_parts]);
+      mode = GET_MODE (var->var_part[i].loc_chain->loc);
       initialized = var->var_part[i].loc_chain->init;
       last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
 
@@ -6365,9 +6427,10 @@ emit_note_insn_var_location (void **varp, void *data)
          break;
       if (j < var->n_var_parts
          && wider_mode != VOIDmode
+         && mode == GET_MODE (var->var_part[j].loc_chain->loc)
+         && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
          && (loc2 = vt_expand_loc (var->var_part[j].loc_chain->loc, vars))
          && GET_CODE (loc[n_var_parts]) == GET_CODE (loc2)
-         && mode == GET_MODE (loc2)
          && last_limit == var->var_part[j].offset)
        {
          rtx new_loc = NULL;
@@ -7058,10 +7121,20 @@ vt_add_function_parameters (void)
 
       if (!vt_get_decl_and_offset (incoming, &decl, &offset))
        {
-         if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
-           continue;
-         offset += byte_lowpart_offset (GET_MODE (incoming),
-                                        GET_MODE (decl_rtl));
+         if (REG_P (incoming) || MEM_P (incoming))
+           {
+             /* This means argument is passed by invisible reference.  */
+             offset = 0;
+             decl = parm;
+             incoming = gen_rtx_MEM (GET_MODE (decl_rtl), incoming);
+           }
+         else
+           {
+             if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
+               continue;
+             offset += byte_lowpart_offset (GET_MODE (incoming),
+                                            GET_MODE (decl_rtl));
+           }
        }
 
       if (!decl)