diff mbox series

[IRA,LRA] Fix PR87466, all pseudos live across setjmp are spilled

Message ID 7f0ff8da-a164-bf05-c668-c69f7b8f314b@linux.ibm.com
State New
Headers show
Series [IRA,LRA] Fix PR87466, all pseudos live across setjmp are spilled | expand

Commit Message

Peter Bergner Sept. 29, 2018, 3:12 a.m. UTC
Currently, both IRA and LRA spill all pseudo regs that are live across a
setjmp call.  If the target has a sane setjmp, then the compiler should not
have to treat the setjmp call any differently than is does any other normal
function call.  Namely, just mark all pseudos that are live across the setjmp
as conflicting with the volatile registers.

This issue was discussed in the following gcc mailing list thread:

  https://gcc.gnu.org/ml/gcc/2018-03/msg00014.html

...and some people mentioned that some systems do not have sane setjmp
implementations and therefore need the spill all pseudos live across setjmps
to get correct functionality.  It was decided in the thread above that we
should create a target hook that can allow targets to tell IRA and LRA
whether or not they have a sane setjmp implementation.  The following patch
implements that idea along with converting the rs6000 port to use the hook.

This patch passed bootstrap and regtesting on powerpc64le-linux with
no regressions.  Ok for trunk?

Peter


gcc/
	PR rtl-optimization/87466
	* target.def (is_reg_clobbering_setjmp_p): New target hook.
	* doc/tm.texi.in (TARGET_IS_REG_CLOBBERING_SETJMP_P): New hook.
	* doc/tm.texi: Regenerate.
	* targhooks.c (default_is_reg_clobbering_setjmp_p): Declare.
	* targhooks.h (default_is_reg_clobbering_setjmp_p): New function.
	* ira-lives.c (process_bb_node_lives): Use the new target hook.
	* lra-lives.c (process_bb_lives): Likewise.
	* config/rs6000/rs6000.c (TARGET_IS_REG_CLOBBERING_SETJMP_P): Define.
	(rs6000_is_reg_clobbering_setjmp_p): New function.

gcc/testsuite/
	PR rtl-optimization/87466
	* gcc.target/powerpc/pr87466.c: New test.

Comments

Richard Biener Oct. 1, 2018, 8:24 a.m. UTC | #1
On Sat, Sep 29, 2018 at 5:12 AM Peter Bergner <bergner@linux.ibm.com> wrote:
>
> Currently, both IRA and LRA spill all pseudo regs that are live across a
> setjmp call.  If the target has a sane setjmp, then the compiler should not
> have to treat the setjmp call any differently than is does any other normal
> function call.  Namely, just mark all pseudos that are live across the setjmp
> as conflicting with the volatile registers.
>
> This issue was discussed in the following gcc mailing list thread:
>
>   https://gcc.gnu.org/ml/gcc/2018-03/msg00014.html
>
> ...and some people mentioned that some systems do not have sane setjmp
> implementations and therefore need the spill all pseudos live across setjmps
> to get correct functionality.  It was decided in the thread above that we
> should create a target hook that can allow targets to tell IRA and LRA
> whether or not they have a sane setjmp implementation.  The following patch
> implements that idea along with converting the rs6000 port to use the hook.
>
> This patch passed bootstrap and regtesting on powerpc64le-linux with
> no regressions.  Ok for trunk?

LGTM.  Please leave others the opportunity to comment.

Thanks,
Richard.

> Peter
>
>
> gcc/
>         PR rtl-optimization/87466
>         * target.def (is_reg_clobbering_setjmp_p): New target hook.
>         * doc/tm.texi.in (TARGET_IS_REG_CLOBBERING_SETJMP_P): New hook.
>         * doc/tm.texi: Regenerate.
>         * targhooks.c (default_is_reg_clobbering_setjmp_p): Declare.
>         * targhooks.h (default_is_reg_clobbering_setjmp_p): New function.
>         * ira-lives.c (process_bb_node_lives): Use the new target hook.
>         * lra-lives.c (process_bb_lives): Likewise.
>         * config/rs6000/rs6000.c (TARGET_IS_REG_CLOBBERING_SETJMP_P): Define.
>         (rs6000_is_reg_clobbering_setjmp_p): New function.
>
> gcc/testsuite/
>         PR rtl-optimization/87466
>         * gcc.target/powerpc/pr87466.c: New test.
>
> Index: gcc/target.def
> ===================================================================
> --- gcc/target.def      (revision 264698)
> +++ gcc/target.def      (working copy)
> @@ -3123,6 +3123,20 @@ In order to enforce the representation o
>   int, (scalar_int_mode mode, scalar_int_mode rep_mode),
>   default_mode_rep_extended)
>
> + DEFHOOK
> +(is_reg_clobbering_setjmp_p,
> + "On some targets, it is assumed that the compiler will spill all registers\n\
> +  that are live across a call to @code{setjmp}, while other targets treat\n\
> +  @code{setjmp} calls as normal function calls.\n\
> +  \n\
> +  This hook returns true if @var{insn} is a @code{setjmp} call that must\n\
> +  have all registers that are live across it spilled.  Define this to return\n\
> +  false if the target does not need to spill all registers across calls to\n\
> +  @code{setjmp} calls.  The default implementation conservatively assumes all\n\
> +  registers must be spilled across @code{setjmp} calls.",
> +bool, (const rtx_insn *insn),
> +default_is_reg_clobbering_setjmp_p)
> +
>  /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))).  */
>  DEFHOOK
>  (valid_pointer_mode,
> Index: gcc/doc/tm.texi.in
> ===================================================================
> --- gcc/doc/tm.texi.in  (revision 264698)
> +++ gcc/doc/tm.texi.in  (working copy)
> @@ -7507,6 +7507,8 @@ You need not define this macro if it wou
>
>  @hook TARGET_MODE_REP_EXTENDED
>
> +@hook TARGET_IS_REG_CLOBBERING_SETJMP_P
> +
>  @defmac STORE_FLAG_VALUE
>  A C expression describing the value returned by a comparison operator
>  with an integral mode and stored by a store-flag instruction
> Index: gcc/doc/tm.texi
> ===================================================================
> --- gcc/doc/tm.texi     (revision 264698)
> +++ gcc/doc/tm.texi     (working copy)
> @@ -11000,6 +11000,18 @@ In order to enforce the representation o
>  @code{mode}.
>  @end deftypefn
>
> +@deftypefn {Target Hook} bool TARGET_IS_REG_CLOBBERING_SETJMP_P (const rtx_insn *@var{insn})
> +On some targets, it is assumed that the compiler will spill all registers
> +  that are live across a call to @code{setjmp}, while other targets treat
> +  @code{setjmp} calls as normal function calls.
> +
> +  This hook returns true if @var{insn} is a @code{setjmp} call that must
> +  have all registers that are live across it spilled.  Define this to return
> +  false if the target does not need to spill all registers across calls to
> +  @code{setjmp} calls.  The default implementation conservatively assumes all
> +  registers must be spilled across @code{setjmp} calls.
> +@end deftypefn
> +
>  @defmac STORE_FLAG_VALUE
>  A C expression describing the value returned by a comparison operator
>  with an integral mode and stored by a store-flag instruction
> Index: gcc/targhooks.c
> ===================================================================
> --- gcc/targhooks.c     (revision 264698)
> +++ gcc/targhooks.c     (working copy)
> @@ -209,6 +209,15 @@ default_builtin_setjmp_frame_value (void
>    return virtual_stack_vars_rtx;
>  }
>
> +/* The default implementation of TARGET_IS_REG_CLOBBERING_SETJMP_P.  */
> +
> +bool
> +default_is_reg_clobbering_setjmp_p (const rtx_insn *insn)
> +{
> +  return CALL_P (insn)
> +        && find_reg_note (insn, REG_SETJMP, NULL_RTX) != NULL_RTX;
> +}
> +
>  /* Generic hook that takes a CUMULATIVE_ARGS pointer and returns false.  */
>
>  bool
> Index: gcc/targhooks.h
> ===================================================================
> --- gcc/targhooks.h     (revision 264698)
> +++ gcc/targhooks.h     (working copy)
> @@ -42,6 +42,7 @@ extern bool default_return_in_memory (co
>  extern rtx default_expand_builtin_saveregs (void);
>  extern void default_setup_incoming_varargs (cumulative_args_t, machine_mode, tree, int *, int);
>  extern rtx default_builtin_setjmp_frame_value (void);
> +extern bool default_is_reg_clobbering_setjmp_p (const rtx_insn *);
>  extern bool default_pretend_outgoing_varargs_named (cumulative_args_t);
>
>  extern scalar_int_mode default_eh_return_filter_mode (void);
> Index: gcc/ira-lives.c
> ===================================================================
> --- gcc/ira-lives.c     (revision 264698)
> +++ gcc/ira-lives.c     (working copy)
> @@ -1209,8 +1209,7 @@ process_bb_node_lives (ira_loop_tree_nod
>                      call, if this function receives a nonlocal
>                      goto.  */
>                   if (cfun->has_nonlocal_label
> -                     || find_reg_note (insn, REG_SETJMP,
> -                                       NULL_RTX) != NULL_RTX)
> +                     || targetm.is_reg_clobbering_setjmp_p (insn))
>                     {
>                       SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
>                       SET_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
> Index: gcc/lra-lives.c
> ===================================================================
> --- gcc/lra-lives.c     (revision 264698)
> +++ gcc/lra-lives.c     (working copy)
> @@ -893,8 +893,7 @@ process_bb_lives (basic_block bb, int &c
>           sparseset_ior (pseudos_live_through_calls,
>                          pseudos_live_through_calls, pseudos_live);
>           if (cfun->has_nonlocal_label
> -             || find_reg_note (curr_insn, REG_SETJMP,
> -                               NULL_RTX) != NULL_RTX)
> +             || targetm.is_reg_clobbering_setjmp_p (curr_insn))
>             sparseset_ior (pseudos_live_through_setjumps,
>                            pseudos_live_through_setjumps, pseudos_live);
>         }
> Index: gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc/config/rs6000/rs6000.c  (revision 264698)
> +++ gcc/config/rs6000/rs6000.c  (working copy)
> @@ -1978,6 +1978,9 @@ static const struct attribute_spec rs600
>  #undef TARGET_ASM_GLOBALIZE_DECL_NAME
>  #define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_globalize_decl_name
>  #endif
> +
> +#undef TARGET_IS_REG_CLOBBERING_SETJMP_P
> +#define TARGET_IS_REG_CLOBBERING_SETJMP_P rs6000_is_reg_clobbering_setjmp_p
>
>
>  /* Processor table.  */
> @@ -38696,6 +38699,14 @@ rs6000_starting_frame_offset (void)
>      return 0;
>    return RS6000_STARTING_FRAME_OFFSET;
>  }
> +
> +/* Implement TARGET_IS_REG_CLOBBERING_SETJMP_P.  */
> +
> +static bool
> +rs6000_is_reg_clobbering_setjmp_p (const rtx_insn *insn ATTRIBUTE_UNUSED)
> +{
> +  return false;
> +}
>
>
>  /* Create an alias for a mangled name where we have changed the mangling (in
> Index: gcc/testsuite/gcc.target/powerpc/pr87466.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/pr87466.c  (nonexistent)
> +++ gcc/testsuite/gcc.target/powerpc/pr87466.c  (working copy)
> @@ -0,0 +1,19 @@
> +/* { dg-do compile { target powerpc*-*-* } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdlib.h>
> +#include <setjmp.h>
> +
> +extern void foo (jmp_buf);
> +
> +long
> +c (long var)
> +{
> +  jmp_buf env;
> +  if (setjmp(env) != 0)
> +    abort();
> +  foo (env);
> +  return var;
> +}
> +
> +/* { dg-final { scan-assembler {\mmr\M} } } */
>
Segher Boessenkool Oct. 1, 2018, 8:40 a.m. UTC | #2
Hi Peter,

On Fri, Sep 28, 2018 at 10:12:02PM -0500, Peter Bergner wrote:
> Currently, both IRA and LRA spill all pseudo regs that are live across a
> setjmp call.  If the target has a sane setjmp, then the compiler should not
> have to treat the setjmp call any differently than is does any other normal
> function call.  Namely, just mark all pseudos that are live across the setjmp
> as conflicting with the volatile registers.
> 
> This issue was discussed in the following gcc mailing list thread:
> 
>   https://gcc.gnu.org/ml/gcc/2018-03/msg00014.html
> 
> ...and some people mentioned that some systems do not have sane setjmp
> implementations and therefore need the spill all pseudos live across setjmps
> to get correct functionality.  It was decided in the thread above that we
> should create a target hook that can allow targets to tell IRA and LRA
> whether or not they have a sane setjmp implementation.  The following patch
> implements that idea along with converting the rs6000 port to use the hook.

> +bool
> +default_is_reg_clobbering_setjmp_p (const rtx_insn *insn)
> +{
> +  return CALL_P (insn)
> +	 && find_reg_note (insn, REG_SETJMP, NULL_RTX) != NULL_RTX;
> +}

Since all implementations of this hook will have to do the same, I think
it is better if you leave this test at the (only two) callers.  The hook
doesn't need an argument then, and maybe is better named something like
setjmp_is_normal_call?  (The original code did not test CALL_P btw).

(Whatever you end up with, the rs6000 part is of course pre-approved).


Segher
Eric Botcazou Oct. 1, 2018, 9:25 a.m. UTC | #3
> Since all implementations of this hook will have to do the same, I think
> it is better if you leave this test at the (only two) callers.  The hook
> doesn't need an argument then, and maybe is better named something like
> setjmp_is_normal_call?  (The original code did not test CALL_P btw).

Seconded, but I'd be even more explicit in the naming of the hook, for example 
setjmp_preserves_nonvolatile_registers or somesuch.  (And I don't think that 
setjmp can be considered a normal call in any case since it returns twice).
Segher Boessenkool Oct. 1, 2018, 10:11 a.m. UTC | #4
On Mon, Oct 01, 2018 at 11:25:21AM +0200, Eric Botcazou wrote:
> > Since all implementations of this hook will have to do the same, I think
> > it is better if you leave this test at the (only two) callers.  The hook
> > doesn't need an argument then, and maybe is better named something like
> > setjmp_is_normal_call?  (The original code did not test CALL_P btw).
> 
> Seconded, but I'd be even more explicit in the naming of the hook, for example 
> setjmp_preserves_nonvolatile_registers or somesuch.  (And I don't think that 
> setjmp can be considered a normal call in any case since it returns twice).

Right...  I meant setjmp has the normal calling convention, the normal
call ABI.  It doesn't really matter to have a longer name here, it is
only used twice (and that code can be factored out to some helper
function, even).


Segher
Peter Bergner Oct. 2, 2018, 4:42 p.m. UTC | #5
On 10/1/18 4:25 AM, Eric Botcazou wrote:
>> Since all implementations of this hook will have to do the same, I think
>> it is better if you leave this test at the (only two) callers.  The hook
>> doesn't need an argument then, and maybe is better named something like
>> setjmp_is_normal_call?  (The original code did not test CALL_P btw).
> 
> Seconded, but I'd be even more explicit in the naming of the hook, for example 
> setjmp_preserves_nonvolatile_registers or somesuch.  (And I don't think that 
> setjmp can be considered a normal call in any case since it returns twice).

Ok, here is an updated patch that renames the hook using Eric's suggestion
and keeps the scanning of the SETJMP note in the callers of the hook like
Segher wanted.

This is currently bootstrapping right now, but ok for trunk assuming no
regressions?

Peter

gcc/
	PR rtl-optimization/87466
	* target.def (setjmp_preserves_nonvolatile_regs_p): New target hook.
	* doc/tm.texi.in (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P): New hook.
	* doc/tm.texi: Regenerate.
	* targhooks.c (default_setjmp_preserves_nonvolatile_regs_p): Declare.
	* targhooks.h (default_setjmp_preserves_nonvolatile_regs_p): New
	function.
	* ira-lives.c (process_bb_node_lives): Use the new target hook.
	* lra-lives.c (process_bb_lives): Likewise.
	* config/rs6000/rs6000.c (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P):
	Define.
	(rs6000_setjmp_preserves_nonvolatile_regs_p): New function.

gcc/testsuite/
	PR rtl-optimization/87466
	* gcc.target/powerpc/pr87466.c: New test.

Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 264795)
+++ gcc/target.def	(working copy)
@@ -3123,6 +3123,21 @@ In order to enforce the representation o
  int, (scalar_int_mode mode, scalar_int_mode rep_mode),
  default_mode_rep_extended)
 
+ DEFHOOK
+(setjmp_preserves_nonvolatile_regs_p,
+ "On some targets, it is assumed that the compiler will spill all pseudos\n\
+  that are live across a call to @code{setjmp}, while other targets treat\n\
+  @code{setjmp} calls as normal function calls.\n\
+  \n\
+  This hook returns false if @code{setjmp} calls do not preserve all\n\
+  non-volatile registers so that gcc that must spill all pseudos that are\n\
+  live across @code{setjmp} calls.  Define this to return true if the\n\
+  target does not need to spill all pseudos live across @code{setjmp} calls.\n\
+  The default implementation conservatively assumes all pseudos must be\n\
+  spilled across @code{setjmp} calls.",
+ bool, (void),
+ default_setjmp_preserves_nonvolatile_regs_p)
+
 /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))).  */
 DEFHOOK
 (valid_pointer_mode,
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 264795)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -7509,6 +7509,8 @@ You need not define this macro if it wou
 
 @hook TARGET_MODE_REP_EXTENDED
 
+@hook TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 264795)
+++ gcc/doc/tm.texi	(working copy)
@@ -11008,6 +11008,19 @@ In order to enforce the representation o
 @code{mode}.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P (void)
+On some targets, it is assumed that the compiler will spill all pseudos
+  that are live across a call to @code{setjmp}, while other targets treat
+  @code{setjmp} calls as normal function calls.
+  
+  This hook returns false if @code{setjmp} calls do not preserve all
+  non-volatile registers so that gcc that must spill all pseudos that are
+  live across @code{setjmp} calls.  Define this to return true if the
+  target does not need to spill all pseudos live across @code{setjmp} calls.
+  The default implementation conservatively assumes all pseudos must be
+  spilled across @code{setjmp} calls.
+@end deftypefn
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 264795)
+++ gcc/targhooks.c	(working copy)
@@ -209,6 +209,14 @@ default_builtin_setjmp_frame_value (void
   return virtual_stack_vars_rtx;
 }
 
+/* The default implementation of TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
+
+bool
+default_setjmp_preserves_nonvolatile_regs_p (void)
+{
+  return false;
+}
+
 /* Generic hook that takes a CUMULATIVE_ARGS pointer and returns false.  */
 
 bool
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 264795)
+++ gcc/targhooks.h	(working copy)
@@ -42,6 +42,7 @@ extern bool default_return_in_memory (co
 extern rtx default_expand_builtin_saveregs (void);
 extern void default_setup_incoming_varargs (cumulative_args_t, machine_mode, tree, int *, int);
 extern rtx default_builtin_setjmp_frame_value (void);
+extern bool default_setjmp_preserves_nonvolatile_regs_p (void);
 extern bool default_pretend_outgoing_varargs_named (cumulative_args_t);
 
 extern scalar_int_mode default_eh_return_filter_mode (void);
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	(revision 264795)
+++ gcc/ira-lives.c	(working copy)
@@ -1207,8 +1207,9 @@ process_bb_node_lives (ira_loop_tree_nod
 		     call, if this function receives a nonlocal
 		     goto.  */
 		  if (cfun->has_nonlocal_label
-		      || find_reg_note (insn, REG_SETJMP,
-					NULL_RTX) != NULL_RTX)
+		      || (!targetm.setjmp_preserves_nonvolatile_regs_p ()
+			  && (find_reg_note (insn, REG_SETJMP, NULL_RTX)
+			      != NULL_RTX)))
 		    {
 		      SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
 		      SET_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
Index: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c	(revision 264795)
+++ gcc/lra-lives.c	(working copy)
@@ -895,8 +895,9 @@ process_bb_lives (basic_block bb, int &c
 	  sparseset_ior (pseudos_live_through_calls,
 			 pseudos_live_through_calls, pseudos_live);
 	  if (cfun->has_nonlocal_label
-	      || find_reg_note (curr_insn, REG_SETJMP,
-				NULL_RTX) != NULL_RTX)
+	      || (!targetm.setjmp_preserves_nonvolatile_regs_p ()
+		  && (find_reg_note (curr_insn, REG_SETJMP, NULL_RTX)
+		      != NULL_RTX)))
 	    sparseset_ior (pseudos_live_through_setjumps,
 			   pseudos_live_through_setjumps, pseudos_live);
 	}
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 264795)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1978,6 +1978,10 @@ static const struct attribute_spec rs600
 #undef TARGET_ASM_GLOBALIZE_DECL_NAME
 #define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_globalize_decl_name
 #endif
+
+#undef TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P
+#define TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P \
+  rs6000_setjmp_preserves_nonvolatile_regs_p
 
 
 /* Processor table.  */
@@ -38872,6 +38876,14 @@ rs6000_starting_frame_offset (void)
     return 0;
   return RS6000_STARTING_FRAME_OFFSET;
 }
+
+/* Implement TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
+
+static bool
+rs6000_setjmp_preserves_nonvolatile_regs_p (void)
+{
+  return true;
+}
 
 
 /* Create an alias for a mangled name where we have changed the mangling (in
Index: gcc/testsuite/gcc.target/powerpc/pr87466.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr87466.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/pr87466.c	(working copy)
@@ -0,0 +1,19 @@
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-options "-O2" } */
+
+#include <stdlib.h>
+#include <setjmp.h>
+
+extern void foo (jmp_buf);
+
+long
+c (long var)
+{
+  jmp_buf env;
+  if (setjmp(env) != 0)
+    abort();
+  foo (env);
+  return var;
+}
+
+/* { dg-final { scan-assembler {\mmr\M} } } */
Peter Bergner Oct. 2, 2018, 5:47 p.m. UTC | #6
On 10/2/18 11:42 AM, Peter Bergner wrote:
> On 10/1/18 4:25 AM, Eric Botcazou wrote:
> This is currently bootstrapping right now, but ok for trunk assuming no
> regressions?
> 
> gcc/
> 	PR rtl-optimization/87466
> 	* target.def (setjmp_preserves_nonvolatile_regs_p): New target hook.
> 	* doc/tm.texi.in (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P): New hook.
> 	* doc/tm.texi: Regenerate.
> 	* targhooks.c (default_setjmp_preserves_nonvolatile_regs_p): Declare.
> 	* targhooks.h (default_setjmp_preserves_nonvolatile_regs_p): New
> 	function.
> 	* ira-lives.c (process_bb_node_lives): Use the new target hook.
> 	* lra-lives.c (process_bb_lives): Likewise.
> 	* config/rs6000/rs6000.c (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P):
> 	Define.
> 	(rs6000_setjmp_preserves_nonvolatile_regs_p): New function.
> 
> gcc/testsuite/
> 	PR rtl-optimization/87466
> 	* gcc.target/powerpc/pr87466.c: New test.

My powerpc64le-linux bootstrap and regtesting showed no regressions.

Peter
Segher Boessenkool Oct. 2, 2018, 6:21 p.m. UTC | #7
Hi Peter,

On Tue, Oct 02, 2018 at 11:42:19AM -0500, Peter Bergner wrote:
> +/* The default implementation of TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
> +
> +bool
> +default_setjmp_preserves_nonvolatile_regs_p (void)
> +{
> +  return false;
> +}

You can just use hook_bool_void_false for this (and hook_bool_void_true
for e.g. the rs6000 implementation).


Segher
Peter Bergner Oct. 2, 2018, 6:34 p.m. UTC | #8
On 10/2/18 1:21 PM, Segher Boessenkool wrote:
> Hi Peter,
> 
> On Tue, Oct 02, 2018 at 11:42:19AM -0500, Peter Bergner wrote:
>> +/* The default implementation of TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
>> +
>> +bool
>> +default_setjmp_preserves_nonvolatile_regs_p (void)
>> +{
>> +  return false;
>> +}
> 
> You can just use hook_bool_void_false for this (and hook_bool_void_true
> for e.g. the rs6000 implementation).

Ah, I didn't know those existed.  Ok, I'll rework it to use that, thanks.

Peter
Peter Bergner Oct. 2, 2018, 6:51 p.m. UTC | #9
On 10/2/18 1:21 PM, Segher Boessenkool wrote:
> On Tue, Oct 02, 2018 at 11:42:19AM -0500, Peter Bergner wrote:
>> +/* The default implementation of TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
>> +
>> +bool
>> +default_setjmp_preserves_nonvolatile_regs_p (void)
>> +{
>> +  return false;
>> +}
> 
> You can just use hook_bool_void_false for this (and hook_bool_void_true
> for e.g. the rs6000 implementation).

Yes, much nicer and smaller patch using those functions!  So here's version 3,
which is the same as version 2 but using above mentioned hook functions.

This is currently bootstrapping right now, ok now assuming no regressions?

Peter

gcc/
	PR rtl-optimization/87466
	* target.def (setjmp_preserves_nonvolatile_regs_p): New target hook.
	* doc/tm.texi.in (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P): New hook.
	* doc/tm.texi: Regenerate.
	* ira-lives.c (process_bb_node_lives): Use the new target hook.
	* lra-lives.c (process_bb_lives): Likewise.
	* config/rs6000/rs6000.c (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P):
	Define.

gcc/testsuite/
	PR rtl-optimization/87466
	* gcc.target/powerpc/pr87466.c: New test.

Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 264795)
+++ gcc/target.def	(working copy)
@@ -3123,6 +3123,21 @@ In order to enforce the representation o
  int, (scalar_int_mode mode, scalar_int_mode rep_mode),
  default_mode_rep_extended)
 
+ DEFHOOK
+(setjmp_preserves_nonvolatile_regs_p,
+ "On some targets, it is assumed that the compiler will spill all pseudos\n\
+  that are live across a call to @code{setjmp}, while other targets treat\n\
+  @code{setjmp} calls as normal function calls.\n\
+  \n\
+  This hook returns false if @code{setjmp} calls do not preserve all\n\
+  non-volatile registers so that gcc that must spill all pseudos that are\n\
+  live across @code{setjmp} calls.  Define this to return true if the\n\
+  target does not need to spill all pseudos live across @code{setjmp} calls.\n\
+  The default implementation conservatively assumes all pseudos must be\n\
+  spilled across @code{setjmp} calls.",
+ bool, (void),
+ hook_bool_void_false)
+
 /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))).  */
 DEFHOOK
 (valid_pointer_mode,
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 264795)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -7509,6 +7509,8 @@ You need not define this macro if it wou
 
 @hook TARGET_MODE_REP_EXTENDED
 
+@hook TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 264795)
+++ gcc/doc/tm.texi	(working copy)
@@ -11008,6 +11008,19 @@ In order to enforce the representation o
 @code{mode}.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P (void)
+On some targets, it is assumed that the compiler will spill all pseudos
+  that are live across a call to @code{setjmp}, while other targets treat
+  @code{setjmp} calls as normal function calls.
+  
+  This hook returns false if @code{setjmp} calls do not preserve all
+  non-volatile registers so that gcc that must spill all pseudos that are
+  live across @code{setjmp} calls.  Define this to return true if the
+  target does not need to spill all pseudos live across @code{setjmp} calls.
+  The default implementation conservatively assumes all pseudos must be
+  spilled across @code{setjmp} calls.
+@end deftypefn
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	(revision 264795)
+++ gcc/ira-lives.c	(working copy)
@@ -1207,8 +1207,9 @@ process_bb_node_lives (ira_loop_tree_nod
 		     call, if this function receives a nonlocal
 		     goto.  */
 		  if (cfun->has_nonlocal_label
-		      || find_reg_note (insn, REG_SETJMP,
-					NULL_RTX) != NULL_RTX)
+		      || (!targetm.setjmp_preserves_nonvolatile_regs_p ()
+			  && (find_reg_note (insn, REG_SETJMP, NULL_RTX)
+			      != NULL_RTX)))
 		    {
 		      SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
 		      SET_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
Index: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c	(revision 264795)
+++ gcc/lra-lives.c	(working copy)
@@ -895,8 +895,9 @@ process_bb_lives (basic_block bb, int &c
 	  sparseset_ior (pseudos_live_through_calls,
 			 pseudos_live_through_calls, pseudos_live);
 	  if (cfun->has_nonlocal_label
-	      || find_reg_note (curr_insn, REG_SETJMP,
-				NULL_RTX) != NULL_RTX)
+	      || (!targetm.setjmp_preserves_nonvolatile_regs_p ()
+		  && (find_reg_note (curr_insn, REG_SETJMP, NULL_RTX)
+		      != NULL_RTX)))
 	    sparseset_ior (pseudos_live_through_setjumps,
 			   pseudos_live_through_setjumps, pseudos_live);
 	}
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 264795)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1978,6 +1978,9 @@ static const struct attribute_spec rs600
 #undef TARGET_ASM_GLOBALIZE_DECL_NAME
 #define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_globalize_decl_name
 #endif
+
+#undef TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P
+#define TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P hook_bool_void_true
 
 
 /* Processor table.  */
Index: gcc/testsuite/gcc.target/powerpc/pr87466.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr87466.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/pr87466.c	(working copy)
@@ -0,0 +1,19 @@
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-options "-O2" } */
+
+#include <stdlib.h>
+#include <setjmp.h>
+
+extern void foo (jmp_buf);
+
+long
+c (long var)
+{
+  jmp_buf env;
+  if (setjmp(env) != 0)
+    abort();
+  foo (env);
+  return var;
+}
+
+/* { dg-final { scan-assembler {\mmr\M} } } */
Vladimir Makarov Oct. 4, 2018, 3:07 a.m. UTC | #10
On 10/02/2018 02:51 PM, Peter Bergner wrote:
> On 10/2/18 1:21 PM, Segher Boessenkool wrote:
>> On Tue, Oct 02, 2018 at 11:42:19AM -0500, Peter Bergner wrote:
>>> +/* The default implementation of TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
>>> +
>>> +bool
>>> +default_setjmp_preserves_nonvolatile_regs_p (void)
>>> +{
>>> +  return false;
>>> +}
>> You can just use hook_bool_void_false for this (and hook_bool_void_true
>> for e.g. the rs6000 implementation).
> Yes, much nicer and smaller patch using those functions!  So here's version 3,
> which is the same as version 2 but using above mentioned hook functions.
>
> This is currently bootstrapping right now, ok now assuming no regressions?
>
Ok for me.  Thank you for working on this issue, Peter.
> gcc/
> 	PR rtl-optimization/87466
> 	* target.def (setjmp_preserves_nonvolatile_regs_p): New target hook.
> 	* doc/tm.texi.in (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P): New hook.
> 	* doc/tm.texi: Regenerate.
> 	* ira-lives.c (process_bb_node_lives): Use the new target hook.
> 	* lra-lives.c (process_bb_lives): Likewise.
> 	* config/rs6000/rs6000.c (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P):
> 	Define.
>
> gcc/testsuite/
> 	PR rtl-optimization/87466
> 	* gcc.target/powerpc/pr87466.c: New test.
Jeff Law Oct. 4, 2018, 3:08 a.m. UTC | #11
On 10/2/18 12:51 PM, Peter Bergner wrote:
> On 10/2/18 1:21 PM, Segher Boessenkool wrote:
>> On Tue, Oct 02, 2018 at 11:42:19AM -0500, Peter Bergner wrote:
>>> +/* The default implementation of TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P.  */
>>> +
>>> +bool
>>> +default_setjmp_preserves_nonvolatile_regs_p (void)
>>> +{
>>> +  return false;
>>> +}
>>
>> You can just use hook_bool_void_false for this (and hook_bool_void_true
>> for e.g. the rs6000 implementation).
> 
> Yes, much nicer and smaller patch using those functions!  So here's version 3,
> which is the same as version 2 but using above mentioned hook functions.
> 
> This is currently bootstrapping right now, ok now assuming no regressions?
> 
> Peter
> 
> gcc/
> 	PR rtl-optimization/87466
> 	* target.def (setjmp_preserves_nonvolatile_regs_p): New target hook.
> 	* doc/tm.texi.in (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P): New hook.
> 	* doc/tm.texi: Regenerate.
> 	* ira-lives.c (process_bb_node_lives): Use the new target hook.
> 	* lra-lives.c (process_bb_lives): Likewise.
> 	* config/rs6000/rs6000.c (TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P):
> 	Define.
> 
> gcc/testsuite/
> 	PR rtl-optimization/87466
> 	* gcc.target/powerpc/pr87466.c: New test.
Given the desire for reload to die and the difficulties testing this
change on a reload target, I don't think mirroring this optimization in
reload is necessary.

OK for the trunk.

jeff
Peter Bergner Oct. 4, 2018, 1:46 p.m. UTC | #12
On 10/3/18 10:08 PM, Jeff Law wrote:
> Given the desire for reload to die and the difficulties testing this
> change on a reload target, I don't think mirroring this optimization in
> reload is necessary.

Right, it's good to have incentives to move away from reload to LRA.
Maybe we could add a few random unneeded conflicts when using reload
to push targets a little more? ;-)


> OK for the trunk.

Thank you everyone for your reviews!  Patch committed.

Peter
diff mbox series

Patch

Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 264698)
+++ gcc/target.def	(working copy)
@@ -3123,6 +3123,20 @@  In order to enforce the representation o
  int, (scalar_int_mode mode, scalar_int_mode rep_mode),
  default_mode_rep_extended)
 
+ DEFHOOK
+(is_reg_clobbering_setjmp_p,
+ "On some targets, it is assumed that the compiler will spill all registers\n\
+  that are live across a call to @code{setjmp}, while other targets treat\n\
+  @code{setjmp} calls as normal function calls.\n\
+  \n\
+  This hook returns true if @var{insn} is a @code{setjmp} call that must\n\
+  have all registers that are live across it spilled.  Define this to return\n\
+  false if the target does not need to spill all registers across calls to\n\
+  @code{setjmp} calls.  The default implementation conservatively assumes all\n\
+  registers must be spilled across @code{setjmp} calls.",
+bool, (const rtx_insn *insn),
+default_is_reg_clobbering_setjmp_p)
+
 /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))).  */
 DEFHOOK
 (valid_pointer_mode,
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 264698)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -7507,6 +7507,8 @@  You need not define this macro if it wou
 
 @hook TARGET_MODE_REP_EXTENDED
 
+@hook TARGET_IS_REG_CLOBBERING_SETJMP_P
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 264698)
+++ gcc/doc/tm.texi	(working copy)
@@ -11000,6 +11000,18 @@  In order to enforce the representation o
 @code{mode}.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_IS_REG_CLOBBERING_SETJMP_P (const rtx_insn *@var{insn})
+On some targets, it is assumed that the compiler will spill all registers
+  that are live across a call to @code{setjmp}, while other targets treat
+  @code{setjmp} calls as normal function calls.
+  
+  This hook returns true if @var{insn} is a @code{setjmp} call that must
+  have all registers that are live across it spilled.  Define this to return
+  false if the target does not need to spill all registers across calls to
+  @code{setjmp} calls.  The default implementation conservatively assumes all
+  registers must be spilled across @code{setjmp} calls.
+@end deftypefn
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 264698)
+++ gcc/targhooks.c	(working copy)
@@ -209,6 +209,15 @@  default_builtin_setjmp_frame_value (void
   return virtual_stack_vars_rtx;
 }
 
+/* The default implementation of TARGET_IS_REG_CLOBBERING_SETJMP_P.  */
+
+bool
+default_is_reg_clobbering_setjmp_p (const rtx_insn *insn)
+{
+  return CALL_P (insn)
+	 && find_reg_note (insn, REG_SETJMP, NULL_RTX) != NULL_RTX;
+}
+
 /* Generic hook that takes a CUMULATIVE_ARGS pointer and returns false.  */
 
 bool
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 264698)
+++ gcc/targhooks.h	(working copy)
@@ -42,6 +42,7 @@  extern bool default_return_in_memory (co
 extern rtx default_expand_builtin_saveregs (void);
 extern void default_setup_incoming_varargs (cumulative_args_t, machine_mode, tree, int *, int);
 extern rtx default_builtin_setjmp_frame_value (void);
+extern bool default_is_reg_clobbering_setjmp_p (const rtx_insn *);
 extern bool default_pretend_outgoing_varargs_named (cumulative_args_t);
 
 extern scalar_int_mode default_eh_return_filter_mode (void);
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	(revision 264698)
+++ gcc/ira-lives.c	(working copy)
@@ -1209,8 +1209,7 @@  process_bb_node_lives (ira_loop_tree_nod
 		     call, if this function receives a nonlocal
 		     goto.  */
 		  if (cfun->has_nonlocal_label
-		      || find_reg_note (insn, REG_SETJMP,
-					NULL_RTX) != NULL_RTX)
+		      || targetm.is_reg_clobbering_setjmp_p (insn))
 		    {
 		      SET_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj));
 		      SET_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
Index: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c	(revision 264698)
+++ gcc/lra-lives.c	(working copy)
@@ -893,8 +893,7 @@  process_bb_lives (basic_block bb, int &c
 	  sparseset_ior (pseudos_live_through_calls,
 			 pseudos_live_through_calls, pseudos_live);
 	  if (cfun->has_nonlocal_label
-	      || find_reg_note (curr_insn, REG_SETJMP,
-				NULL_RTX) != NULL_RTX)
+	      || targetm.is_reg_clobbering_setjmp_p (curr_insn))
 	    sparseset_ior (pseudos_live_through_setjumps,
 			   pseudos_live_through_setjumps, pseudos_live);
 	}
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 264698)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1978,6 +1978,9 @@  static const struct attribute_spec rs600
 #undef TARGET_ASM_GLOBALIZE_DECL_NAME
 #define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_globalize_decl_name
 #endif
+
+#undef TARGET_IS_REG_CLOBBERING_SETJMP_P
+#define TARGET_IS_REG_CLOBBERING_SETJMP_P rs6000_is_reg_clobbering_setjmp_p
 
 
 /* Processor table.  */
@@ -38696,6 +38699,14 @@  rs6000_starting_frame_offset (void)
     return 0;
   return RS6000_STARTING_FRAME_OFFSET;
 }
+
+/* Implement TARGET_IS_REG_CLOBBERING_SETJMP_P.  */
+
+static bool
+rs6000_is_reg_clobbering_setjmp_p (const rtx_insn *insn ATTRIBUTE_UNUSED)
+{
+  return false;
+}
 
 
 /* Create an alias for a mangled name where we have changed the mangling (in
Index: gcc/testsuite/gcc.target/powerpc/pr87466.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr87466.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/pr87466.c	(working copy)
@@ -0,0 +1,19 @@ 
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-options "-O2" } */
+
+#include <stdlib.h>
+#include <setjmp.h>
+
+extern void foo (jmp_buf);
+
+long
+c (long var)
+{
+  jmp_buf env;
+  if (setjmp(env) != 0)
+    abort();
+  foo (env);
+  return var;
+}
+
+/* { dg-final { scan-assembler {\mmr\M} } } */