On Sat, Nov 21, 2015 at 11:19:57AM -0800, H.J. Lu wrote: > When implementing interrupt attribute for x86 interrupt handlers, we > have a difficult time to access interrupt data passed down by x86 > processors. On x86, interrupt handlers are only called by processors > which push interrupt data onto stack at the address where the normal > return address is. Interrupt handlers must access interrupt data via > pointers so that they can update interrupt data. > > TARGET_FUNCTION_ARG_ADVANCE is skipped by interrupt handlers since they > are only called by processors. Since interrupt data is at one word > below the normal argument location on stack and must be accessed via > pointer, we changed TARGET_FUNCTION_ARG to return a fake hard register > for interrupt handlers and updated expander to covert the fake register > to its address on stack. > > However, we run into problems with > > /* For PARM_DECL, holds an RTL for the stack slot or register > where the data was actually passed. */ > #define DECL_INCOMING_RTL(NODE) \ > (PARM_DECL_CHECK (NODE)->parm_decl.incoming_rtl) > > >From what I can tell, DECL_INCOMING_RTL is a constant after it is set up. > For interrupt handlers, DECL_INCOMING_RTL contains a fake register, > which isn't a problem in codegen since it is covered by expander. But > DECL_INCOMING_RTL is also used to generate debug information and debug > output never expects a fake register in DECL_INCOMING_RTL. To work around > it, we changed x86 prologue expander to update DECL_INCOMING_RTL with the > fake register in interrupt handlers to its address on stack. > > We are asking middle-end maintainers, is this a correct solution? If not, > what other approaches should we try? > >
A target machine may have a special DECL_INCOMING_RTL which must be converted for the correct location. This patch adds a target hook to get the location where the argument will appear to the callee. The default is DECL_INCOMING_RTL. It replaces DECL_INCOMING_RTL with get_decl_incoming_rtl when DECL_INCOMING_RTL is used to get the location. Only DWARF debug output is updated since DBX and SDB debug formats can't handle "(plus:DI (reg/f:DI 16 argp) (const_int -8))" for a pointer argument. Does it make sense? Thanks. H.J. ---- * combine.c (setup_incoming_promotions): Replace DECL_INCOMING_RTL with get_decl_incoming_rtl. * dwarf2out.c (add_var_loc_to_decl): Likewise. (rtl_for_decl_location): Likewise. * var-tracking.c (add_stores): Likewise. (vt_add_function_parameter): Likewise. * emit-rtl.c (get_decl_incoming_rtl): New function. * targhooks.c (default_function_incoming_arg_rtl): Likewise. * emit-rtl.h (get_decl_incoming_rtl): New prototype. * targhooks.h (default_function_incoming_arg_rtl): Likewise. * target.def (function_incoming_arg_rtl): New hook. * doc/tm.texi.in: Add TARGET_FUNCTION_INCOMING_ARG_RTL. * doc/tm.texi: Updated. --- gcc/combine.c | 2 +- gcc/doc/tm.texi | 8 ++++++++ gcc/doc/tm.texi.in | 2 ++ gcc/dwarf2out.c | 21 ++++++++++++--------- gcc/emit-rtl.c | 8 ++++++++ gcc/emit-rtl.h | 1 + gcc/target.def | 12 ++++++++++++ gcc/targhooks.c | 6 ++++++ gcc/targhooks.h | 1 + gcc/var-tracking.c | 19 +++++++++++-------- 10 files changed, 62 insertions(+), 18 deletions(-) diff --git a/gcc/combine.c b/gcc/combine.c index 2a66fd5..01c43a2 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -1543,7 +1543,7 @@ setup_incoming_promotions (rtx_insn *first) for (arg = DECL_ARGUMENTS (current_function_decl); arg; arg = DECL_CHAIN (arg)) { - rtx x, reg = DECL_INCOMING_RTL (arg); + rtx x, reg = get_decl_incoming_rtl (arg); int uns1, uns3; machine_mode mode1, mode2, mode3, mode4; diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index bde808b..b727f20 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3953,6 +3953,14 @@ If @code{TARGET_FUNCTION_INCOMING_ARG} is not defined, @code{TARGET_FUNCTION_ARG} serves both purposes. @end deftypefn +@deftypefn {Target Hook} rtx TARGET_FUNCTION_INCOMING_ARG_RTL (const_tree @var{parmdecl}) +Define this hook if the target machine has a special @code{DECL_INCOMING_RTL} +which must be converted for the correct location. + +If @code{TARGET_FUNCTION_INCOMING_ARG_RTL} is not defined, +@code{DECL_INCOMING_RTL} of the input @var{parmdecl} will be used. +@end deftypefn + @deftypefn {Target Hook} bool TARGET_USE_PSEUDO_PIC_REG (void) This hook should return 1 in case pseudo register should be created for pic_offset_table_rtx during function expand. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 0677fc1..dbd1f0b 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3369,6 +3369,8 @@ the stack. @hook TARGET_FUNCTION_INCOMING_ARG +@hook TARGET_FUNCTION_INCOMING_ARG_RTL + @hook TARGET_USE_PSEUDO_PIC_REG @hook TARGET_INIT_PIC_REG diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index f184750..1b8b7b2 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -5300,6 +5300,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) else temp = *slot; + rtx incoming_rtl; /* For PARM_DECLs try to keep around the original incoming value, even if that means we'll emit a zero-range .debug_loc entry. */ if (temp->last @@ -5307,10 +5308,10 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) && TREE_CODE (decl) == PARM_DECL && NOTE_P (temp->first->loc) && NOTE_VAR_LOCATION_DECL (temp->first->loc) == decl - && DECL_INCOMING_RTL (decl) + && (incoming_rtl = get_decl_incoming_rtl (decl)) && NOTE_VAR_LOCATION_LOC (temp->first->loc) && GET_CODE (NOTE_VAR_LOCATION_LOC (temp->first->loc)) - == GET_CODE (DECL_INCOMING_RTL (decl)) + == GET_CODE (incoming_rtl) && prev_real_insn (temp->first->loc) == NULL_RTX && (bitsize != -1 || !rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->first->loc), @@ -15972,13 +15973,15 @@ rtl_for_decl_location (tree decl) } else if (TREE_CODE (decl) == PARM_DECL) { + rtx incoming_rtl = get_decl_incoming_rtl (decl); + if (rtl == NULL_RTX || is_pseudo_reg (rtl) || (MEM_P (rtl) && is_pseudo_reg (XEXP (rtl, 0)) - && DECL_INCOMING_RTL (decl) - && MEM_P (DECL_INCOMING_RTL (decl)) - && GET_MODE (rtl) == GET_MODE (DECL_INCOMING_RTL (decl)))) + && incoming_rtl + && MEM_P (incoming_rtl) + && GET_MODE (rtl) == GET_MODE (incoming_rtl))) { tree declared_type = TREE_TYPE (decl); tree passed_type = DECL_ARG_TYPE (decl); @@ -15989,13 +15992,13 @@ rtl_for_decl_location (tree decl) Note that DECL_INCOMING_RTL may be NULL in here, but we handle all cases where (rtl == NULL_RTX) just below. */ if (dmode == pmode) - rtl = DECL_INCOMING_RTL (decl); + rtl = incoming_rtl; else if ((rtl == NULL_RTX || is_pseudo_reg (rtl)) && SCALAR_INT_MODE_P (dmode) && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode) - && DECL_INCOMING_RTL (decl)) + && incoming_rtl) { - rtx inc = DECL_INCOMING_RTL (decl); + rtx inc = incoming_rtl; if (REG_P (inc)) rtl = inc; else if (MEM_P (inc)) @@ -16021,7 +16024,7 @@ rtl_for_decl_location (tree decl) && XEXP (rtl, 0) != const0_rtx && ! CONSTANT_P (XEXP (rtl, 0)) /* Not passed in memory. */ - && !MEM_P (DECL_INCOMING_RTL (decl)) + && !MEM_P (incoming_rtl) /* Not passed by invisible reference. */ && (!REG_P (XEXP (rtl, 0)) || REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index c6a37e1..53ae12b 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1290,6 +1290,14 @@ set_decl_incoming_rtl (tree t, rtx x, bool by_reference_p) set_reg_attrs_for_decl_rtl (t, x); } +/* Return the location where the argument appears to the callee. */ + +rtx +get_decl_incoming_rtl (const_tree parmdecl) +{ + return targetm.calls.function_incoming_arg_rtl (parmdecl); +} + /* Identify REG (which may be a CONCAT) as a user register. */ void diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h index f52c335..b48c721 100644 --- a/gcc/emit-rtl.h +++ b/gcc/emit-rtl.h @@ -430,6 +430,7 @@ get_max_uid (void) } extern void set_decl_incoming_rtl (tree, rtx, bool); +extern rtx get_decl_incoming_rtl (const_tree); /* Return a memory reference like MEMREF, but with its mode changed to MODE and its address changed to ADDR. diff --git a/gcc/target.def b/gcc/target.def index b0ad09e..979bd5f 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4493,6 +4493,18 @@ If @code{TARGET_FUNCTION_INCOMING_ARG} is not defined,\n\ bool named), default_function_incoming_arg) +/* Return the location where the argument will appear to the callee. */ +DEFHOOK +(function_incoming_arg_rtl, + "Define this hook if the target machine has a special\ + @code{DECL_INCOMING_RTL}\n\ +which must be converted for the correct location.\n\ +\n\ +If @code{TARGET_FUNCTION_INCOMING_ARG_RTL} is not defined,\n\ +@code{DECL_INCOMING_RTL} of the input @var{parmdecl} will be used.", + rtx, (const_tree parmdecl), + default_function_incoming_arg_rtl) + DEFHOOK (function_arg_boundary, "This hook returns the alignment boundary, in bits, of an argument\n\ diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 01d3686..7449b36 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -661,6 +661,12 @@ default_function_incoming_arg (cumulative_args_t ca ATTRIBUTE_UNUSED, gcc_unreachable (); } +rtx +default_function_incoming_arg_rtl (const_tree parmdecl) +{ + return DECL_INCOMING_RTL (parmdecl); +} + unsigned int default_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED, const_tree type ATTRIBUTE_UNUSED) diff --git a/gcc/targhooks.h b/gcc/targhooks.h index f5d04e6..ca5bf48 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -135,6 +135,7 @@ extern rtx default_function_arg (cumulative_args_t, machine_mode, const_tree, bool); extern rtx default_function_incoming_arg (cumulative_args_t, machine_mode, const_tree, bool); +extern rtx default_function_incoming_arg_rtl (const_tree); extern unsigned int default_function_arg_boundary (machine_mode, const_tree); extern unsigned int default_function_arg_round_boundary (machine_mode, diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 9185bfd..9dde705 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -5809,9 +5809,13 @@ add_stores (rtx loc, const_rtx expr, void *cuip) mode2 = mode; + rtx incoming_rtl = NULL; + if (REG_P (loc)) { gcc_assert (loc != cfa_base_rtx); + if (REG_EXPR (loc) && TREE_CODE (REG_EXPR (loc)) == PARM_DECL) + incoming_rtl = get_decl_incoming_rtl (REG_EXPR (loc)); if ((GET_CODE (expr) == CLOBBER && type != MO_VAL_SET) || !(track_p = use_type (loc, NULL, &mode2) == MO_USE) || GET_CODE (expr) == CLOBBER) @@ -5855,9 +5859,8 @@ add_stores (rtx loc, const_rtx expr, void *cuip) && REG_EXPR (loc) && TREE_CODE (REG_EXPR (loc)) == PARM_DECL && DECL_MODE (REG_EXPR (loc)) != BLKmode - && MEM_P (DECL_INCOMING_RTL (REG_EXPR (loc))) - && XEXP (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) - != arg_pointer_rtx) + && MEM_P (incoming_rtl) + && XEXP (incoming_rtl, 0) != arg_pointer_rtx) mo.type = MO_SET; else mo.type = MO_COPY; @@ -5941,10 +5944,10 @@ add_stores (rtx loc, const_rtx expr, void *cuip) && TREE_CODE (REG_EXPR (loc)) == PARM_DECL && DECL_MODE (REG_EXPR (loc)) != BLKmode && TREE_CODE (TREE_TYPE (REG_EXPR (loc))) != UNION_TYPE - && ((MEM_P (DECL_INCOMING_RTL (REG_EXPR (loc))) - && XEXP (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) != arg_pointer_rtx) - || (GET_CODE (DECL_INCOMING_RTL (REG_EXPR (loc))) == PARALLEL - && XVECLEN (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) > 1))) + && ((MEM_P (incoming_rtl) + && XEXP (incoming_rtl, 0) != arg_pointer_rtx) + || (GET_CODE (incoming_rtl) == PARALLEL + && XVECLEN (incoming_rtl, 0) > 1))) { /* Although we don't use the value here, it could be used later by the mere virtue of its existence as the operand of the reverse operation @@ -9506,7 +9509,7 @@ static void vt_add_function_parameter (tree parm) { rtx decl_rtl = DECL_RTL_IF_SET (parm); - rtx incoming = DECL_INCOMING_RTL (parm); + rtx incoming = get_decl_incoming_rtl (parm); tree decl; machine_mode mode; HOST_WIDE_INT offset; -- 2.4.3