builtins: Commonise default handling of nonlocal_goto
Checks
Commit Message
expand_builtin_longjmp and expand_builtin_nonlocal_goto both
emit nonlocal gotos. They first try to use a target-provided
pattern and fall back to generic code otherwise. These pieces
of generic code are almost identical, and having them inline
like this makes it difficult to define a nonlocal_goto pattern
that only wants to add extra steps, not change the default ones.
Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install?
Richard
gcc/
* builtins.h (emit_standard_nonlocal_goto): Declare.
* builtins.cc (emit_standard_nonlocal_goto): New function,
commonizing code from...
(expand_builtin_longjmp, expand_builtin_nonlocal_goto): ...here.
* genemit.cc (main): Emit an include of builtins.h.
---
gcc/builtins.cc | 103 +++++++++++++++++++++---------------------------
gcc/builtins.h | 1 +
gcc/genemit.cc | 1 +
3 files changed, 47 insertions(+), 58 deletions(-)
Comments
On Sun, Nov 13, 2022 at 10:33 AM Richard Sandiford via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> expand_builtin_longjmp and expand_builtin_nonlocal_goto both
> emit nonlocal gotos. They first try to use a target-provided
> pattern and fall back to generic code otherwise. These pieces
> of generic code are almost identical, and having them inline
> like this makes it difficult to define a nonlocal_goto pattern
> that only wants to add extra steps, not change the default ones.
>
> Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install?
OK.
> Richard
>
> gcc/
> * builtins.h (emit_standard_nonlocal_goto): Declare.
> * builtins.cc (emit_standard_nonlocal_goto): New function,
> commonizing code from...
> (expand_builtin_longjmp, expand_builtin_nonlocal_goto): ...here.
> * genemit.cc (main): Emit an include of builtins.h.
> ---
> gcc/builtins.cc | 103 +++++++++++++++++++++---------------------------
> gcc/builtins.h | 1 +
> gcc/genemit.cc | 1 +
> 3 files changed, 47 insertions(+), 58 deletions(-)
>
> diff --git a/gcc/builtins.cc b/gcc/builtins.cc
> index 4dc1ca672b2..2507745c17a 100644
> --- a/gcc/builtins.cc
> +++ b/gcc/builtins.cc
> @@ -998,6 +998,49 @@ expand_builtin_setjmp_receiver (rtx receiver_label)
> emit_insn (gen_blockage ());
> }
>
> +/* Emit the standard sequence for a nonlocal_goto. The arguments are
> + the operands to the .md pattern. */
> +
> +void
> +emit_standard_nonlocal_goto (rtx value, rtx label, rtx stack, rtx fp)
> +{
> + emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
> + emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
> +
> + label = copy_to_reg (label);
> +
> + /* Restore the frame pointer and stack pointer. We must use a
> + temporary since the setjmp buffer may be a local. */
> + fp = copy_to_reg (fp);
> + emit_stack_restore (SAVE_NONLOCAL, stack);
> +
> + /* Ensure the frame pointer move is not optimized. */
> + emit_insn (gen_blockage ());
> + emit_clobber (hard_frame_pointer_rtx);
> + emit_clobber (frame_pointer_rtx);
> + emit_move_insn (hard_frame_pointer_rtx, fp);
> +
> + /* USE of hard_frame_pointer_rtx added for consistency;
> + not clear if really needed. */
> + emit_use (hard_frame_pointer_rtx);
> + emit_use (stack_pointer_rtx);
> +
> + /* If the architecture is using a GP register, we must
> + conservatively assume that the target function makes use of it.
> + The prologue of functions with nonlocal gotos must therefore
> + initialize the GP register to the appropriate value, and we
> + must then make sure that this value is live at the point
> + of the jump. (Note that this doesn't necessarily apply
> + to targets with a nonlocal_goto pattern; they are free
> + to implement it in their own way. Note also that this is
> + a no-op if the GP register is a global invariant.) */
> + unsigned regnum = PIC_OFFSET_TABLE_REGNUM;
> + if (value == const0_rtx && regnum != INVALID_REGNUM && fixed_regs[regnum])
> + emit_use (pic_offset_table_rtx);
> +
> + emit_indirect_jump (label);
> +}
> +
> /* __builtin_longjmp is passed a pointer to an array of five words (not
> all will be used on all machines). It operates similarly to the C
> library function of the same name, but is more efficient. Much of
> @@ -1049,27 +1092,7 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
> what that value is, because builtin_setjmp does not use it. */
> emit_insn (targetm.gen_nonlocal_goto (value, lab, stack, fp));
> else
> - {
> - emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
> - emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
> -
> - lab = copy_to_reg (lab);
> -
> - /* Restore the frame pointer and stack pointer. We must use a
> - temporary since the setjmp buffer may be a local. */
> - fp = copy_to_reg (fp);
> - emit_stack_restore (SAVE_NONLOCAL, stack);
> -
> - /* Ensure the frame pointer move is not optimized. */
> - emit_insn (gen_blockage ());
> - emit_clobber (hard_frame_pointer_rtx);
> - emit_clobber (frame_pointer_rtx);
> - emit_move_insn (hard_frame_pointer_rtx, fp);
> -
> - emit_use (hard_frame_pointer_rtx);
> - emit_use (stack_pointer_rtx);
> - emit_indirect_jump (lab);
> - }
> + emit_standard_nonlocal_goto (value, lab, stack, fp);
> }
>
> /* Search backwards and mark the jump insn as a non-local goto.
> @@ -1201,43 +1224,7 @@ expand_builtin_nonlocal_goto (tree exp)
> if (targetm.have_nonlocal_goto ())
> emit_insn (targetm.gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp));
> else
> - {
> - emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
> - emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
> -
> - r_label = copy_to_reg (r_label);
> -
> - /* Restore the frame pointer and stack pointer. We must use a
> - temporary since the setjmp buffer may be a local. */
> - r_fp = copy_to_reg (r_fp);
> - emit_stack_restore (SAVE_NONLOCAL, r_sp);
> -
> - /* Ensure the frame pointer move is not optimized. */
> - emit_insn (gen_blockage ());
> - emit_clobber (hard_frame_pointer_rtx);
> - emit_clobber (frame_pointer_rtx);
> - emit_move_insn (hard_frame_pointer_rtx, r_fp);
> -
> - /* USE of hard_frame_pointer_rtx added for consistency;
> - not clear if really needed. */
> - emit_use (hard_frame_pointer_rtx);
> - emit_use (stack_pointer_rtx);
> -
> - /* If the architecture is using a GP register, we must
> - conservatively assume that the target function makes use of it.
> - The prologue of functions with nonlocal gotos must therefore
> - initialize the GP register to the appropriate value, and we
> - must then make sure that this value is live at the point
> - of the jump. (Note that this doesn't necessarily apply
> - to targets with a nonlocal_goto pattern; they are free
> - to implement it in their own way. Note also that this is
> - a no-op if the GP register is a global invariant.) */
> - unsigned regnum = PIC_OFFSET_TABLE_REGNUM;
> - if (regnum != INVALID_REGNUM && fixed_regs[regnum])
> - emit_use (pic_offset_table_rtx);
> -
> - emit_indirect_jump (r_label);
> - }
> + emit_standard_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp);
>
> /* Search backwards to the jump insn and mark it as a
> non-local goto. */
> diff --git a/gcc/builtins.h b/gcc/builtins.h
> index 5ad830c9fbf..5c86b241fea 100644
> --- a/gcc/builtins.h
> +++ b/gcc/builtins.h
> @@ -150,6 +150,7 @@ extern char target_percent_c[3];
> extern char target_percent_s_newline[4];
> extern bool target_char_cst_p (tree t, char *p);
> extern rtx get_memory_rtx (tree exp, tree len);
> +extern void emit_standard_nonlocal_goto (rtx, rtx, rtx, rtx);
>
> extern internal_fn associated_internal_fn (combined_fn, tree);
> extern internal_fn associated_internal_fn (tree);
> diff --git a/gcc/genemit.cc b/gcc/genemit.cc
> index 909ac89a16b..c3e2152a491 100644
> --- a/gcc/genemit.cc
> +++ b/gcc/genemit.cc
> @@ -905,6 +905,7 @@ from the machine description file `md'. */\n\n");
> printf ("#include \"tm-constrs.h\"\n");
> printf ("#include \"ggc.h\"\n");
> printf ("#include \"target.h\"\n\n");
> + printf ("#include \"builtins.h\"\n\n");
>
> /* Read the machine description. */
>
> --
> 2.25.1
>
@@ -998,6 +998,49 @@ expand_builtin_setjmp_receiver (rtx receiver_label)
emit_insn (gen_blockage ());
}
+/* Emit the standard sequence for a nonlocal_goto. The arguments are
+ the operands to the .md pattern. */
+
+void
+emit_standard_nonlocal_goto (rtx value, rtx label, rtx stack, rtx fp)
+{
+ emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+ emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
+
+ label = copy_to_reg (label);
+
+ /* Restore the frame pointer and stack pointer. We must use a
+ temporary since the setjmp buffer may be a local. */
+ fp = copy_to_reg (fp);
+ emit_stack_restore (SAVE_NONLOCAL, stack);
+
+ /* Ensure the frame pointer move is not optimized. */
+ emit_insn (gen_blockage ());
+ emit_clobber (hard_frame_pointer_rtx);
+ emit_clobber (frame_pointer_rtx);
+ emit_move_insn (hard_frame_pointer_rtx, fp);
+
+ /* USE of hard_frame_pointer_rtx added for consistency;
+ not clear if really needed. */
+ emit_use (hard_frame_pointer_rtx);
+ emit_use (stack_pointer_rtx);
+
+ /* If the architecture is using a GP register, we must
+ conservatively assume that the target function makes use of it.
+ The prologue of functions with nonlocal gotos must therefore
+ initialize the GP register to the appropriate value, and we
+ must then make sure that this value is live at the point
+ of the jump. (Note that this doesn't necessarily apply
+ to targets with a nonlocal_goto pattern; they are free
+ to implement it in their own way. Note also that this is
+ a no-op if the GP register is a global invariant.) */
+ unsigned regnum = PIC_OFFSET_TABLE_REGNUM;
+ if (value == const0_rtx && regnum != INVALID_REGNUM && fixed_regs[regnum])
+ emit_use (pic_offset_table_rtx);
+
+ emit_indirect_jump (label);
+}
+
/* __builtin_longjmp is passed a pointer to an array of five words (not
all will be used on all machines). It operates similarly to the C
library function of the same name, but is more efficient. Much of
@@ -1049,27 +1092,7 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
what that value is, because builtin_setjmp does not use it. */
emit_insn (targetm.gen_nonlocal_goto (value, lab, stack, fp));
else
- {
- emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
- emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
-
- lab = copy_to_reg (lab);
-
- /* Restore the frame pointer and stack pointer. We must use a
- temporary since the setjmp buffer may be a local. */
- fp = copy_to_reg (fp);
- emit_stack_restore (SAVE_NONLOCAL, stack);
-
- /* Ensure the frame pointer move is not optimized. */
- emit_insn (gen_blockage ());
- emit_clobber (hard_frame_pointer_rtx);
- emit_clobber (frame_pointer_rtx);
- emit_move_insn (hard_frame_pointer_rtx, fp);
-
- emit_use (hard_frame_pointer_rtx);
- emit_use (stack_pointer_rtx);
- emit_indirect_jump (lab);
- }
+ emit_standard_nonlocal_goto (value, lab, stack, fp);
}
/* Search backwards and mark the jump insn as a non-local goto.
@@ -1201,43 +1224,7 @@ expand_builtin_nonlocal_goto (tree exp)
if (targetm.have_nonlocal_goto ())
emit_insn (targetm.gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp));
else
- {
- emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
- emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
-
- r_label = copy_to_reg (r_label);
-
- /* Restore the frame pointer and stack pointer. We must use a
- temporary since the setjmp buffer may be a local. */
- r_fp = copy_to_reg (r_fp);
- emit_stack_restore (SAVE_NONLOCAL, r_sp);
-
- /* Ensure the frame pointer move is not optimized. */
- emit_insn (gen_blockage ());
- emit_clobber (hard_frame_pointer_rtx);
- emit_clobber (frame_pointer_rtx);
- emit_move_insn (hard_frame_pointer_rtx, r_fp);
-
- /* USE of hard_frame_pointer_rtx added for consistency;
- not clear if really needed. */
- emit_use (hard_frame_pointer_rtx);
- emit_use (stack_pointer_rtx);
-
- /* If the architecture is using a GP register, we must
- conservatively assume that the target function makes use of it.
- The prologue of functions with nonlocal gotos must therefore
- initialize the GP register to the appropriate value, and we
- must then make sure that this value is live at the point
- of the jump. (Note that this doesn't necessarily apply
- to targets with a nonlocal_goto pattern; they are free
- to implement it in their own way. Note also that this is
- a no-op if the GP register is a global invariant.) */
- unsigned regnum = PIC_OFFSET_TABLE_REGNUM;
- if (regnum != INVALID_REGNUM && fixed_regs[regnum])
- emit_use (pic_offset_table_rtx);
-
- emit_indirect_jump (r_label);
- }
+ emit_standard_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp);
/* Search backwards to the jump insn and mark it as a
non-local goto. */
@@ -150,6 +150,7 @@ extern char target_percent_c[3];
extern char target_percent_s_newline[4];
extern bool target_char_cst_p (tree t, char *p);
extern rtx get_memory_rtx (tree exp, tree len);
+extern void emit_standard_nonlocal_goto (rtx, rtx, rtx, rtx);
extern internal_fn associated_internal_fn (combined_fn, tree);
extern internal_fn associated_internal_fn (tree);
@@ -905,6 +905,7 @@ from the machine description file `md'. */\n\n");
printf ("#include \"tm-constrs.h\"\n");
printf ("#include \"ggc.h\"\n");
printf ("#include \"target.h\"\n\n");
+ printf ("#include \"builtins.h\"\n\n");
/* Read the machine description. */