diff mbox

Fix up call_site_parameter (PR debug/50299)

Message ID 20110906124000.GI2687@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Sept. 6, 2011, 12:40 p.m. UTC
Hi!

CALL_INSN_FUNCTION_USAGE contains for each (use (reg:M)) or (use (mem:M))
the mode of the promoted argument, not the original mode, which is needed
for RTL optimizations, but prepare_call_arguments would like to know
the original non-promoted argument mode (i.e. TYPE_MODE of the argument's
type).  While sometimes prepare_call_arguments can get at the tree type
of the callee, for e.g. indirect calls that information is simply not
available.  And without that information, e.g. if on a big-endian
64-bit hosts an argument is passed on the stack promoted from SImode to
DImode, we store the address of the whole 64-bit slot instead of adding
+4 to it to get at the 32-bit slot where the actual int argument is passed.

The following patch fixes it by not storing just one mode - the promoted
mode - in C_I_F_U, but also storing there the original mode as well.
The advantage of that is that various non-argument USEs in C_I_F_U will
no longer be tracked as DW_TAG_call_site_parameter - e.g. x86_64 %al
for var-arg functions which is passed the number of SSE arguments.
The original mode is stored in EXPR_LIST's mode.

I've adjusted just the single register arguments (which on various targets
includes even multi-word arguments, as long as the registers are consecutive
etc.) and memory slots, not sure what to do with multi-register arguments,
so I've left them with VOIDmode (this could be changed by adjusting
use_group_regs and/or use_regs).  We do a terribly bad job debug-info wise
for testcases like
struct S { long a, b; };
void baz (void);

__attribute__((noinline, noclone))
int foo (struct S s)
{
  long a = s.a;
  long b = s.b;
  baz ();
  return 2;
}

int bar (void)
{
  struct S s = { 1, 2 };
  foo (s);
  return 0;
}
on x86_64-linux anyway - var-tracking doesn't track those, RTL DSE removes
the argument stores (so debug_insns for e.g. a and b above reference
uninitialized memory) and DECL_RTL of the parameter is used too (so again,
the same uninitialized memory).  Maybe we could for small arguments (say up
to 4 or 8 words) attempt to track them by pieces during var-tracking, as
if SRA split them up, if their DECL_RTL isn't the memory slot in which they
have been passed.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2011-09-06  Jakub Jelinek  <jakub@redhat.com>

	PR debug/50299
	* calls.c (load_register_parameters): Use use_reg_mode instead
	of use_reg when adding a single register CALL_INSN_FUNCTION_USAGE
	entry.
	(expand_call): Set EXPR_LIST mode to TYPE_MODE of the argument
	for stack CALL_INSN_FUNCTION_USAGE uses.
	* expr.h (use_reg_mode): New prototype.
	(use_reg): Changed into inline around use_reg_mode.
	* expr.c (use_reg): Renamed to...
	(use_reg_mode): ... this.  Added MODE argument, set EXPR_LIST
	mode to that mode instead of VOIDmode.
	* var-tracking.c (prepare_call_arguments): Don't track parameters
	whose EXPR_LIST mode is VOIDmode, BLKmode or X mode isn't convertible
	to it using lowpart_subreg.  Convert VALUE and REG/MEM to the
	EXPR_LIST mode.


	Jakub

Comments

Richard Sandiford Sept. 12, 2011, 11:54 a.m. UTC | #1
Jakub Jelinek <jakub@redhat.com> writes:
> 2011-09-06  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR debug/50299
> 	* calls.c (load_register_parameters): Use use_reg_mode instead
> 	of use_reg when adding a single register CALL_INSN_FUNCTION_USAGE
> 	entry.
> 	(expand_call): Set EXPR_LIST mode to TYPE_MODE of the argument
> 	for stack CALL_INSN_FUNCTION_USAGE uses.
> 	* expr.h (use_reg_mode): New prototype.
> 	(use_reg): Changed into inline around use_reg_mode.
> 	* expr.c (use_reg): Renamed to...
> 	(use_reg_mode): ... this.  Added MODE argument, set EXPR_LIST
> 	mode to that mode instead of VOIDmode.
> 	* var-tracking.c (prepare_call_arguments): Don't track parameters
> 	whose EXPR_LIST mode is VOIDmode, BLKmode or X mode isn't convertible
> 	to it using lowpart_subreg.  Convert VALUE and REG/MEM to the
> 	EXPR_LIST mode.

Looks good to me FWIW, but I can't approve it.

Richard
diff mbox

Patch

--- gcc/calls.c.jj	2011-08-22 08:17:07.000000000 +0200
+++ gcc/calls.c	2011-09-05 19:47:47.000000000 +0200
@@ -1756,7 +1756,8 @@  load_register_parameters (struct arg_dat
 	  if (GET_CODE (reg) == PARALLEL)
 	    use_group_regs (call_fusage, reg);
 	  else if (nregs == -1)
-	    use_reg (call_fusage, reg);
+	    use_reg_mode (call_fusage, reg,
+			  TYPE_MODE (TREE_TYPE (args[i].tree_value)));
 	  else if (nregs > 0)
 	    use_regs (call_fusage, REGNO (reg), nregs);
 	}
@@ -2815,10 +2816,10 @@  expand_call (tree exp, rtx target, int i
 	      }
 
 	  if (args[i].stack)
-	    call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
-					     gen_rtx_USE (VOIDmode,
-							  args[i].stack),
-					     call_fusage);
+	    call_fusage
+	      = gen_rtx_EXPR_LIST (TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+				   gen_rtx_USE (VOIDmode, args[i].stack),
+				   call_fusage);
 	}
 
       /* If we have a parm that is passed in registers but not in memory
--- gcc/expr.h.jj	2011-07-27 23:25:36.000000000 +0200
+++ gcc/expr.h	2011-09-05 18:05:31.000000000 +0200
@@ -321,8 +321,16 @@  extern void emit_group_store (rtx, rtx, 
 /* Copy BLKmode object from a set of registers.  */
 extern rtx copy_blkmode_from_reg (rtx, rtx, tree);
 
+/* Mark REG as holding a parameter for the next CALL_INSN.
+   Mode is TYPE_MODE of the non-promoted parameter, or VOIDmode.  */
+extern void use_reg_mode (rtx *, rtx, enum machine_mode);
+
 /* Mark REG as holding a parameter for the next CALL_INSN.  */
-extern void use_reg (rtx *, rtx);
+static inline void
+use_reg (rtx *fusage, rtx reg)
+{
+  use_reg_mode (fusage, reg, VOIDmode);
+}
 
 /* Mark NREGS consecutive regs, starting at REGNO, as holding parameters
    for the next CALL_INSN.  */
--- gcc/expr.c.jj	2011-09-02 16:29:39.000000000 +0200
+++ gcc/expr.c	2011-09-05 19:47:32.000000000 +0200
@@ -2184,13 +2184,12 @@  copy_blkmode_from_reg (rtx tgtblk, rtx s
    to by CALL_FUSAGE.  REG must denote a hard register.  */
 
 void
-use_reg (rtx *call_fusage, rtx reg)
+use_reg_mode (rtx *call_fusage, rtx reg, enum machine_mode mode)
 {
   gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
 
   *call_fusage
-    = gen_rtx_EXPR_LIST (VOIDmode,
-			 gen_rtx_USE (VOIDmode, reg), *call_fusage);
+    = gen_rtx_EXPR_LIST (mode, gen_rtx_USE (VOIDmode, reg), *call_fusage);
 }
 
 /* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs,
--- gcc/var-tracking.c.jj	2011-08-30 10:52:41.000000000 +0200
+++ gcc/var-tracking.c	2011-09-05 19:48:10.000000000 +0200
@@ -5730,11 +5730,18 @@  prepare_call_arguments (basic_block bb, 
       {
 	rtx item = NULL_RTX;
 	x = XEXP (XEXP (link, 0), 0);
-	if (REG_P (x))
+	if (GET_MODE (link) == VOIDmode
+	    || GET_MODE (link) == BLKmode
+	    || (GET_MODE (link) != GET_MODE (x)
+		&& (GET_MODE_CLASS (GET_MODE (link)) != MODE_INT
+		    || GET_MODE_CLASS (GET_MODE (x)) != MODE_INT)))
+	  /* Can't do anything for these, if the original type mode
+	     isn't known or can't be converted.  */;
+	else if (REG_P (x))
 	  {
 	    cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
 	    if (val && cselib_preserved_value_p (val))
-	      item = gen_rtx_CONCAT (GET_MODE (x), x, val->val_rtx);
+	      item = val->val_rtx;
 	    else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
 	      {
 		enum machine_mode mode = GET_MODE (x);
@@ -5749,10 +5756,7 @@  prepare_call_arguments (basic_block bb, 
 		    val = cselib_lookup (reg, mode, 0, VOIDmode);
 		    if (val && cselib_preserved_value_p (val))
 		      {
-			item = gen_rtx_CONCAT (GET_MODE (x), x,
-					       lowpart_subreg (GET_MODE (x),
-							       val->val_rtx,
-							       mode));
+			item = val->val_rtx;
 			break;
 		      }
 		  }
@@ -5776,7 +5780,7 @@  prepare_call_arguments (basic_block bb, 
 	      }
 	    val = cselib_lookup (mem, GET_MODE (mem), 0, VOIDmode);
 	    if (val && cselib_preserved_value_p (val))
-	      item = gen_rtx_CONCAT (GET_MODE (x), copy_rtx (x), val->val_rtx);
+	      item = val->val_rtx;
 	    else if (GET_MODE_CLASS (GET_MODE (mem)) != MODE_INT)
 	      {
 		/* For non-integer stack argument see also if they weren't
@@ -5787,15 +5791,22 @@  prepare_call_arguments (basic_block bb, 
 		    val = cselib_lookup (adjust_address_nv (mem, imode, 0),
 					 imode, 0, VOIDmode);
 		    if (val && cselib_preserved_value_p (val))
-		      item = gen_rtx_CONCAT (GET_MODE (x), copy_rtx (x),
-					     lowpart_subreg (GET_MODE (x),
-							     val->val_rtx,
-							     imode));
+		      item = lowpart_subreg (GET_MODE (x), val->val_rtx,
+					     imode);
 		  }
 	      }
 	  }
 	if (item)
-	  call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
+	  {
+	    rtx x2 = x;
+	    if (GET_MODE (item) != GET_MODE (link))
+	      item = lowpart_subreg (GET_MODE (link), item, GET_MODE (item));
+	    if (GET_MODE (x2) != GET_MODE (link))
+	      x2 = lowpart_subreg (GET_MODE (link), x2, GET_MODE (x2));
+	    item = gen_rtx_CONCAT (GET_MODE (link), x2, item);
+	    call_arguments
+	      = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
+	  }
 	if (t && t != void_list_node)
 	  {
 	    tree argtype = TREE_VALUE (t);