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 <ja...@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. --- 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); Jakub