diff mbox

Add TARGET_FUNCTION_INCOMING_ARG_RTL

Message ID 20151122134928.GA8596@gmail.com
State New
Headers show

Commit Message

H.J. Lu Nov. 22, 2015, 1:49 p.m. UTC
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 mbox

Patch

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;