This patch adds a new rtx code for capturing a decl's DECL_RTL by reference rather than by value. When used in a VAR_LOCATION, the VAR_LOCATION continues to track the decl as it changes over time, rather than "remembering" the value that the decl had at the point of the VAR_LOCATION.
2019-06-01 Richard Sandiford <richard.sandif...@arm.com> gcc/ * rtl.def (DEF_RTL_EXPR): New rtx code. * doc/rtl.texi: Document it. * rtl.h (DECL_RTL_REF_TARGET): New macro. * rtl.c (rtx_equal_p_cb, rtx_equal_p): Handle DEF_RTL_EXPR. * alias.c (rtx_equal_for_memref_p): Likewise. * cselib.c (invariant_or_equiv_p, rtx_equal_for_cselib_1) (cselib_hash_rtx): Likewise. * dwarf2out.c (mem_loc_descriptor): Likewise. * print-rtl.c (rtx_writer::print_rtx_operand): Likewise. Index: gcc/rtl.def =================================================================== --- gcc/rtl.def 2019-05-31 17:27:35.155089238 +0100 +++ gcc/rtl.def 2019-06-01 16:38:31.985677188 +0100 @@ -775,6 +775,11 @@ DEF_RTL_EXPR(DEBUG_IMPLICIT_PTR, "debug_ parameter. */ DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ) +/* Captures the DECL_RTL of a DECL by reference rather than by value, + so that it tracks the DECL_RTL as it evolves over time. The single + argument is the DECL, accessed via DECL_RTL_REF_TARGET. */ +DEF_RTL_EXPR(DECL_RTL_REF, "decl_rtl_ref", "t", RTX_OBJ) + /* Used in VAR_LOCATION for a reference to a parameter that has been optimized away completely. */ DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ) Index: gcc/doc/rtl.texi =================================================================== --- gcc/doc/rtl.texi 2019-03-08 18:14:25.581010702 +0000 +++ gcc/doc/rtl.texi 2019-06-01 16:38:31.969677234 +0100 @@ -3675,6 +3675,14 @@ Stands for the location of a @var{decl} Stands for the value a @var{decl} had at the entry point of the containing function. +@findex decl_rtl_ref +@item (decl_rtl_ref:@var{mode} @var{decl}) +Captures @samp{DECL_RTL (@var{decl})} by reference rather than by value, +so that it tracks the @code{DECL_RTL} as it evolves over time. This is +useful for describing the debug location of a variable that spends part +of its lifetime in memory and that can be indirectly modified while +stored in memory. + @findex debug_parameter_ref @item (debug_parameter_ref:@var{mode} @var{decl}) Refers to a parameter that was completely optimized out. @@ -4018,11 +4026,20 @@ temporaries and determining expressions value of each user variable at as many points (ranges, actually) in the program as possible. -Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an -@code{INSN_VAR_LOCATION} denotes a value at that specific point in the -program, rather than an expression that can be evaluated at any later -point before an overriding @code{VAR_LOCATION} is encountered. E.g., -if a user variable is bound to a @code{REG} and then a subsequent insn +@findex decl_rtl_ref +@code{INSN_VAR_LOCATION} and @code{NOTE_INSN_VAR_LOCATION} differ in the +way that they ``capture'' potentially-variable parts of an expression. +An @code{INSN_VAR_LOCATION} captures any potentially-variable subexpression +@emph{by value} unless it contains an explicit by-reference capture +such as @code{decl_rtl_ref}. A @code{NOTE_INSN_VAR_LOCATION} +instead captures @emph{every} subexpression by reference. + +Capturing a subexpression @var{x} by value means that the subexpression +represents the value @var{x} had at that particular point in time. +Capturing by reference means that the subexpression tracks the value +of @var{x} as it evolves over time. + +E.g., if a user variable is bound to a @code{REG} and then a subsequent insn modifies the @code{REG}, the note location would keep mapping the user variable to the register across the insn, whereas the insn location would keep the variable bound to the value, so that the variable Index: gcc/rtl.h =================================================================== --- gcc/rtl.h 2019-05-29 10:49:39.892700893 +0100 +++ gcc/rtl.h 2019-06-01 16:38:31.985677188 +0100 @@ -1608,6 +1608,9 @@ #define REG_NOTES(INSN) XEXP(INSN, 6) question. */ #define ENTRY_VALUE_EXP(RTX) (RTL_CHECKC1 (RTX, 0, ENTRY_VALUE).rt_rtx) +/* The decl referenced by a DECL_RTL_REF. */ +#define DECL_RTL_REF_TARGET(RTX) (RTL_CHECKC1 (RTX, 0, DECL_RTL_REF).rt_tree) + enum reg_note { #define DEF_REG_NOTE(NAME) NAME, Index: gcc/rtl.c =================================================================== --- gcc/rtl.c 2019-04-26 10:59:07.730195479 +0100 +++ gcc/rtl.c 2019-06-01 16:38:31.985677188 +0100 @@ -486,6 +486,9 @@ rtx_equal_p_cb (const_rtx x, const_rtx y case ENTRY_VALUE: return rtx_equal_p_cb (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y), cb); + case DECL_RTL_REF: + return DECL_RTL_REF_TARGET (x) == DECL_RTL_REF_TARGET (y); + default: break; } @@ -628,6 +631,9 @@ rtx_equal_p (const_rtx x, const_rtx y) case ENTRY_VALUE: return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y)); + case DECL_RTL_REF: + return DECL_RTL_REF_TARGET (x) == DECL_RTL_REF_TARGET (y); + default: break; } Index: gcc/alias.c =================================================================== --- gcc/alias.c 2019-05-29 10:49:39.520701975 +0100 +++ gcc/alias.c 2019-06-01 16:38:31.969677234 +0100 @@ -1769,6 +1769,9 @@ rtx_equal_for_memref_p (const_rtx x, con /* This is magic, don't go through canonicalization et al. */ return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y)); + case DECL_RTL_REF: + return DECL_RTL_REF_TARGET (x) == DECL_RTL_REF_TARGET (y); + case VALUE: CASE_CONST_UNIQUE: /* Pointer equality guarantees equality for these nodes. */ Index: gcc/cselib.c =================================================================== --- gcc/cselib.c 2019-03-08 18:15:33.700751752 +0000 +++ gcc/cselib.c 2019-06-01 16:38:31.969677234 +0100 @@ -466,6 +466,7 @@ invariant_or_equiv_p (cselib_val *v) if (GET_CODE (v->locs->loc) == DEBUG_EXPR || GET_CODE (v->locs->loc) == DEBUG_IMPLICIT_PTR || GET_CODE (v->locs->loc) == ENTRY_VALUE + || GET_CODE (v->locs->loc) == DECL_RTL_REF || GET_CODE (v->locs->loc) == DEBUG_PARAMETER_REF) return true; @@ -952,6 +953,9 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, ma use rtx_equal_for_cselib_1 to compare the operands. */ return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y)); + case DECL_RTL_REF: + return DECL_RTL_REF_TARGET (x) == DECL_RTL_REF_TARGET (y); + case LABEL_REF: return label_ref_label (x) == label_ref_label (y); @@ -1126,6 +1130,11 @@ cselib_hash_rtx (rtx x, int create, mach hash += cselib_hash_rtx (ENTRY_VALUE_EXP (x), create, memmode); return hash ? hash : (unsigned int) ENTRY_VALUE; + case DECL_RTL_REF: + hash += ((unsigned) DECL_RTL_REF << 7) + + DECL_UID (DECL_RTL_REF_TARGET (x)); + return hash ? hash : (unsigned int) DECL_RTL_REF; + case CONST_INT: hash += ((unsigned) CONST_INT << 7) + UINTVAL (x); return hash ? hash : (unsigned int) CONST_INT; Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c 2019-05-29 10:49:38.836703961 +0100 +++ gcc/dwarf2out.c 2019-06-01 16:38:31.977677211 +0100 @@ -15855,6 +15855,10 @@ mem_loc_descriptor (rtx rtl, machine_mod mem_loc_result->dw_loc_oprnd1.v.val_loc = op0; break; + case DECL_RTL_REF: + return mem_loc_descriptor (DECL_RTL (DECL_RTL_REF_TARGET (rtl)), + mode, mem_mode, initialized); + case DEBUG_PARAMETER_REF: mem_loc_result = parameter_ref_descriptor (rtl); break; Index: gcc/print-rtl.c =================================================================== --- gcc/print-rtl.c 2019-03-08 18:15:33.660751905 +0000 +++ gcc/print-rtl.c 2019-06-01 16:38:31.981677200 +0100 @@ -678,6 +678,8 @@ rtx_writer::print_rtx_operand (const_rtx print_mem_expr (m_outfile, DEBUG_IMPLICIT_PTR_DECL (in_rtx)); else if (idx == 0 && GET_CODE (in_rtx) == DEBUG_PARAMETER_REF) print_mem_expr (m_outfile, DEBUG_PARAMETER_REF_DECL (in_rtx)); + else if (idx == 0 && GET_CODE (in_rtx) == DECL_RTL_REF) + print_mem_expr (m_outfile, DECL_RTL_REF_TARGET (in_rtx)); else dump_addr (m_outfile, " ", XTREE (in_rtx, idx)); #endif