This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Add TARGET_FUNCTION_INCOMING_ARG_RTL
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: gcc-patches at gcc dot gnu dot org, Jeffrey Law <law at redhat dot com>, Richard Biener <richard dot guenther at gmail dot com>
- Date: Sun, 22 Nov 2015 05:49:28 -0800
- Subject: [PATCH] Add TARGET_FUNCTION_INCOMING_ARG_RTL
- Authentication-results: sourceware.org; auth=none
- References: <CAMe9rOqL7O7jbGHCH3T8GT1GU0nCHJqXpw06YBnhf4S+ix_GAQ at mail dot gmail dot com>
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