]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cfgexpand.c
re PR debug/47858 (IPA-SRA decreases quality of debug info)
[thirdparty/gcc.git] / gcc / cfgexpand.c
index efd3ed93c36bf0bfc29c7eeedf288915f5a87a75..000a790a683694f4301c302df5314c6519cc14db 100644 (file)
@@ -57,6 +57,8 @@ struct ssaexpand SA;
    of comminucating the profile info to the builtin expanders.  */
 gimple currently_expanding_gimple_stmt;
 
+static rtx expand_debug_expr (tree);
+
 /* Return an expression tree corresponding to the RHS of GIMPLE
    statement STMT.  */
 
@@ -1863,6 +1865,21 @@ expand_call_stmt (gimple stmt)
   SET_EXPR_LOCATION (exp, gimple_location (stmt));
   TREE_BLOCK (exp) = gimple_block (stmt);
 
+  /* Ensure RTL is created for debug args.  */
+  if (decl && DECL_HAS_DEBUG_ARGS_P (decl))
+    {
+      VEC(tree, gc) **debug_args = decl_debug_args_lookup (decl);
+      unsigned int ix;
+      tree dtemp;
+
+      if (debug_args)
+       for (ix = 1; VEC_iterate (tree, *debug_args, ix, dtemp); ix += 2)
+         {
+           gcc_assert (TREE_CODE (dtemp) == DEBUG_EXPR_DECL);
+           expand_debug_expr (dtemp);
+         }
+    }
+
   lhs = gimple_call_lhs (stmt);
   if (lhs)
     expand_assignment (lhs, exp, false);
@@ -3297,6 +3314,120 @@ expand_debug_expr (tree exp)
     }
 }
 
+/* Return an RTX equivalent to the source bind value of the tree expression
+   EXP.  */
+
+static rtx
+expand_debug_source_expr (tree exp)
+{
+  rtx op0 = NULL_RTX;
+  enum machine_mode mode = VOIDmode, inner_mode;
+
+  switch (TREE_CODE (exp))
+    {
+    case PARM_DECL:
+      {
+       rtx incoming = DECL_INCOMING_RTL (exp);
+       mode = DECL_MODE (exp);
+       if (incoming
+           && GET_MODE (incoming) != BLKmode
+           && ((REG_P (incoming) && HARD_REGISTER_P (incoming))
+               || (MEM_P (incoming)
+                   && REG_P (XEXP (incoming, 0))
+                   && HARD_REGISTER_P (XEXP (incoming, 0)))))
+         {
+           op0 = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
+           ENTRY_VALUE_EXP (op0) = incoming;
+           break;
+         }
+       if (incoming
+           && MEM_P (incoming)
+           && !TREE_ADDRESSABLE (exp)
+           && GET_MODE (incoming) != BLKmode
+           && (XEXP (incoming, 0) == virtual_incoming_args_rtx
+               || (GET_CODE (XEXP (incoming, 0)) == PLUS
+                   && XEXP (XEXP (incoming, 0), 0)
+                      == virtual_incoming_args_rtx
+                   && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
+         {
+           op0 = incoming;
+           break;
+         }
+       /* See if this isn't an argument that has been completely
+          optimized out.  */
+       if (!DECL_RTL_SET_P (exp)
+           && incoming == NULL_RTX
+           && DECL_ABSTRACT_ORIGIN (current_function_decl))
+         {
+           tree aexp = exp;
+           if (DECL_ABSTRACT_ORIGIN (exp))
+             aexp = DECL_ABSTRACT_ORIGIN (exp);
+           if (DECL_CONTEXT (aexp)
+               == DECL_ABSTRACT_ORIGIN (current_function_decl))
+             {
+               VEC(tree, gc) **debug_args;
+               unsigned int ix;
+               tree ddecl;
+#ifdef ENABLE_CHECKING
+               tree parm;
+               for (parm = DECL_ARGUMENTS (current_function_decl);
+                    parm; parm = DECL_CHAIN (parm))
+                 gcc_assert (parm != exp
+                             && DECL_ABSTRACT_ORIGIN (parm) != aexp);
+#endif
+               debug_args = decl_debug_args_lookup (current_function_decl);
+               if (debug_args != NULL)
+                 {
+                   for (ix = 0; VEC_iterate (tree, *debug_args, ix, ddecl);
+                        ix += 2)
+                     if (ddecl == aexp)
+                       return gen_rtx_DEBUG_PARAMETER_REF (mode, aexp);
+                 }
+             }
+         }
+       break;
+      }
+    default:
+      break;
+    }
+
+  if (op0 == NULL_RTX)
+    return NULL_RTX;
+
+  inner_mode = GET_MODE (op0);
+  if (mode == inner_mode)
+    return op0;
+
+  if (FLOAT_MODE_P (mode) && FLOAT_MODE_P (inner_mode))
+    {
+      if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (inner_mode))
+       op0 = simplify_gen_subreg (mode, op0, inner_mode, 0);
+      else if (GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (inner_mode))
+       op0 = simplify_gen_unary (FLOAT_TRUNCATE, mode, op0, inner_mode);
+      else
+       op0 = simplify_gen_unary (FLOAT_EXTEND, mode, op0, inner_mode);
+    }
+  else if (FLOAT_MODE_P (mode))
+    gcc_unreachable ();
+  else if (FLOAT_MODE_P (inner_mode))
+    {
+      if (TYPE_UNSIGNED (TREE_TYPE (exp)))
+       op0 = simplify_gen_unary (UNSIGNED_FIX, mode, op0, inner_mode);
+      else
+       op0 = simplify_gen_unary (FIX, mode, op0, inner_mode);
+    }
+  else if (CONSTANT_P (op0)
+          || GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (inner_mode))
+    op0 = simplify_gen_subreg (mode, op0, inner_mode,
+                              subreg_lowpart_offset (mode, inner_mode));
+  else if (TYPE_UNSIGNED (TREE_TYPE (exp)))
+    op0 = simplify_gen_unary (ZERO_EXTEND, mode, op0, inner_mode);
+  else
+    op0 = simplify_gen_unary (SIGN_EXTEND, mode, op0, inner_mode);
+
+  return op0;
+}
+
 /* Expand the _LOCs in debug insns.  We run this after expanding all
    regular insns, so that any variables referenced in the function
    will have their DECL_RTLs set.  */
@@ -3324,7 +3455,11 @@ expand_debug_locations (void)
          val = NULL_RTX;
        else
          {
-           val = expand_debug_expr (value);
+           if (INSN_VAR_LOCATION_STATUS (insn)
+               == VAR_INIT_STATUS_UNINITIALIZED)
+             val = expand_debug_source_expr (value);
+           else
+             val = expand_debug_expr (value);
            gcc_assert (last == get_last_insn ());
          }
 
@@ -3603,6 +3738,39 @@ expand_gimple_basic_block (basic_block bb)
                break;
            }
 
+         set_curr_insn_source_location (sloc);
+         set_curr_insn_block (sblock);
+       }
+      else if (gimple_debug_source_bind_p (stmt))
+       {
+         location_t sloc = get_curr_insn_source_location ();
+         tree sblock = get_curr_insn_block ();
+         tree var = gimple_debug_source_bind_get_var (stmt);
+         tree value = gimple_debug_source_bind_get_value (stmt);
+         rtx val;
+         enum machine_mode mode;
+
+         last = get_last_insn ();
+
+         set_curr_insn_source_location (gimple_location (stmt));
+         set_curr_insn_block (gimple_block (stmt));
+
+         mode = DECL_MODE (var);
+
+         val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+                                     VAR_INIT_STATUS_UNINITIALIZED);
+
+         emit_debug_insn (val);
+
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             /* We can't dump the insn with a TREE where an RTX
+                is expected.  */
+             PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+             maybe_dump_rtl_for_gimple_stmt (stmt, last);
+             PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+           }
+
          set_curr_insn_source_location (sloc);
          set_curr_insn_block (sblock);
        }