diff mbox series

x86: Update BB_HEAD when aligning BB_HEAD

Message ID 20240809015310.673857-1-hjl.tools@gmail.com
State New
Headers show
Series x86: Update BB_HEAD when aligning BB_HEAD | expand

Commit Message

H.J. Lu Aug. 9, 2024, 1:53 a.m. UTC
When we emit .p2align to align BB_HEAD, we must update BB_HEAD.  Otherwise
ENDBR will be inserted as the wrong place.

gcc/

	PR target/116174
	* config/i386/i386.cc (ix86_align_loops): Update BB_HEAD when
	aligning BB_HEAD

gcc/testsuite/

	PR target/116174
	* gcc.target/i386/pr116174.c: New test.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 gcc/config/i386/i386.cc                  |  7 +++++--
 gcc/testsuite/gcc.target/i386/pr116174.c | 12 ++++++++++++
 2 files changed, 17 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr116174.c

Comments

H.J. Lu Aug. 11, 2024, 10:58 p.m. UTC | #1
On Thu, Aug 8, 2024 at 6:53 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> When we emit .p2align to align BB_HEAD, we must update BB_HEAD.  Otherwise
> ENDBR will be inserted as the wrong place.
>
> gcc/
>
>         PR target/116174
>         * config/i386/i386.cc (ix86_align_loops): Update BB_HEAD when
>         aligning BB_HEAD
>
> gcc/testsuite/
>
>         PR target/116174
>         * gcc.target/i386/pr116174.c: New test.
>
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
>  gcc/config/i386/i386.cc                  |  7 +++++--
>  gcc/testsuite/gcc.target/i386/pr116174.c | 12 ++++++++++++
>  2 files changed, 17 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr116174.c
>
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index 77c441893b4..ec6cc5e3548 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -23528,8 +23528,11 @@ ix86_align_loops ()
>
>           if (padding_p && detect_tight_loop_p)
>             {
> -             emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> -                                                   GEN_INT (0)), label);
> +             rtx_insn *align =
> +               emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> +                                                     GEN_INT (0)), label);
> +             if (BB_HEAD (bb) == label)
> +               BB_HEAD (bb) = align;
>               /* End of function.  */
>               if (!tbb || tbb == EXIT_BLOCK_PTR_FOR_FN (cfun))
>                 break;
> diff --git a/gcc/testsuite/gcc.target/i386/pr116174.c b/gcc/testsuite/gcc.target/i386/pr116174.c
> new file mode 100644
> index 00000000000..8877d0b51af
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr116174.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target *-*-linux* } } */
> +/* { dg-options "-O2 -fcf-protection=branch" } */
> +
> +char *
> +foo (char *dest, const char *src)
> +{
> +  while ((*dest++ = *src++) != '\0')
> +    /* nothing */;
> +  return --dest;
> +}
> +
> +/* { dg-final { scan-assembler "\t\.cfi_startproc\n\tendbr(32|64)\n" } } */
> --
> 2.45.2
>

PING.
Hongtao Liu Aug. 12, 2024, 2:05 a.m. UTC | #2
On Mon, Aug 12, 2024 at 6:59 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Thu, Aug 8, 2024 at 6:53 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > When we emit .p2align to align BB_HEAD, we must update BB_HEAD.  Otherwise
> > ENDBR will be inserted as the wrong place.
> >
> > gcc/
> >
> >         PR target/116174
> >         * config/i386/i386.cc (ix86_align_loops): Update BB_HEAD when
> >         aligning BB_HEAD
> >
> > gcc/testsuite/
> >
> >         PR target/116174
> >         * gcc.target/i386/pr116174.c: New test.
> >
> > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > ---
> >  gcc/config/i386/i386.cc                  |  7 +++++--
> >  gcc/testsuite/gcc.target/i386/pr116174.c | 12 ++++++++++++
> >  2 files changed, 17 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr116174.c
> >
> > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > index 77c441893b4..ec6cc5e3548 100644
> > --- a/gcc/config/i386/i386.cc
> > +++ b/gcc/config/i386/i386.cc
> > @@ -23528,8 +23528,11 @@ ix86_align_loops ()
> >
> >           if (padding_p && detect_tight_loop_p)
> >             {
> > -             emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> > -                                                   GEN_INT (0)), label);
> > +             rtx_insn *align =
> > +               emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> > +                                                     GEN_INT (0)), label);
> > +             if (BB_HEAD (bb) == label)
> > +               BB_HEAD (bb) = align;
Are there any assumptions that BB_HEAD must be a note or label?
Maybe we should move ix86_align_loops into a separate pass and insert
the pass just before pass_final.

> >               /* End of function.  */
> >               if (!tbb || tbb == EXIT_BLOCK_PTR_FOR_FN (cfun))
> >                 break;
> > diff --git a/gcc/testsuite/gcc.target/i386/pr116174.c b/gcc/testsuite/gcc.target/i386/pr116174.c
> > new file mode 100644
> > index 00000000000..8877d0b51af
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/i386/pr116174.c
> > @@ -0,0 +1,12 @@
> > +/* { dg-do compile { target *-*-linux* } } */
> > +/* { dg-options "-O2 -fcf-protection=branch" } */
> > +
> > +char *
> > +foo (char *dest, const char *src)
> > +{
> > +  while ((*dest++ = *src++) != '\0')
> > +    /* nothing */;
> > +  return --dest;
> > +}
> > +
> > +/* { dg-final { scan-assembler "\t\.cfi_startproc\n\tendbr(32|64)\n" } } */
> > --
> > 2.45.2
> >
>
> PING.
>
> --
> H.J.
H.J. Lu Aug. 12, 2024, 3:21 a.m. UTC | #3
On Sun, Aug 11, 2024 at 6:52 PM Hongtao Liu <crazylht@gmail.com> wrote:
>
> On Mon, Aug 12, 2024 at 6:59 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Thu, Aug 8, 2024 at 6:53 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > When we emit .p2align to align BB_HEAD, we must update BB_HEAD.  Otherwise
> > > ENDBR will be inserted as the wrong place.
> > >
> > > gcc/
> > >
> > >         PR target/116174
> > >         * config/i386/i386.cc (ix86_align_loops): Update BB_HEAD when
> > >         aligning BB_HEAD
> > >
> > > gcc/testsuite/
> > >
> > >         PR target/116174
> > >         * gcc.target/i386/pr116174.c: New test.
> > >
> > > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > > ---
> > >  gcc/config/i386/i386.cc                  |  7 +++++--
> > >  gcc/testsuite/gcc.target/i386/pr116174.c | 12 ++++++++++++
> > >  2 files changed, 17 insertions(+), 2 deletions(-)
> > >  create mode 100644 gcc/testsuite/gcc.target/i386/pr116174.c
> > >
> > > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > > index 77c441893b4..ec6cc5e3548 100644
> > > --- a/gcc/config/i386/i386.cc
> > > +++ b/gcc/config/i386/i386.cc
> > > @@ -23528,8 +23528,11 @@ ix86_align_loops ()
> > >
> > >           if (padding_p && detect_tight_loop_p)
> > >             {
> > > -             emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> > > -                                                   GEN_INT (0)), label);
> > > +             rtx_insn *align =
> > > +               emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> > > +                                                     GEN_INT (0)), label);
> > > +             if (BB_HEAD (bb) == label)
> > > +               BB_HEAD (bb) = align;
> Are there any assumptions that BB_HEAD must be a note or label?

I don't know.  But LABEL may be BB_HEAD.

> Maybe we should move ix86_align_loops into a separate pass and insert
> the pass just before pass_final.
>
> > >               /* End of function.  */
> > >               if (!tbb || tbb == EXIT_BLOCK_PTR_FOR_FN (cfun))
> > >                 break;
> > > diff --git a/gcc/testsuite/gcc.target/i386/pr116174.c b/gcc/testsuite/gcc.target/i386/pr116174.c
> > > new file mode 100644
> > > index 00000000000..8877d0b51af
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/i386/pr116174.c
> > > @@ -0,0 +1,12 @@
> > > +/* { dg-do compile { target *-*-linux* } } */
> > > +/* { dg-options "-O2 -fcf-protection=branch" } */
> > > +
> > > +char *
> > > +foo (char *dest, const char *src)
> > > +{
> > > +  while ((*dest++ = *src++) != '\0')
> > > +    /* nothing */;
> > > +  return --dest;
> > > +}
> > > +
> > > +/* { dg-final { scan-assembler "\t\.cfi_startproc\n\tendbr(32|64)\n" } } */
> > > --
> > > 2.45.2
> > >
> >
> > PING.
> >
> > --
> > H.J.
>
>
>
> --
> BR,
> Hongtao
Jakub Jelinek Aug. 12, 2024, 7:25 a.m. UTC | #4
On Thu, Aug 08, 2024 at 06:53:10PM -0700, H.J. Lu wrote:
> When we emit .p2align to align BB_HEAD, we must update BB_HEAD.  Otherwise
> ENDBR will be inserted as the wrong place.
> 
> gcc/
> 
> 	PR target/116174
> 	* config/i386/i386.cc (ix86_align_loops): Update BB_HEAD when
> 	aligning BB_HEAD
> 
> gcc/testsuite/
> 
> 	PR target/116174
> 	* gcc.target/i386/pr116174.c: New test.
> 
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
>  gcc/config/i386/i386.cc                  |  7 +++++--
>  gcc/testsuite/gcc.target/i386/pr116174.c | 12 ++++++++++++
>  2 files changed, 17 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr116174.c
> 
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index 77c441893b4..ec6cc5e3548 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -23528,8 +23528,11 @@ ix86_align_loops ()
>  
>  	  if (padding_p && detect_tight_loop_p)
>  	    {
> -	      emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> -						    GEN_INT (0)), label);
> +	      rtx_insn *align =

= can't go at the end of line.

> +		emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> +						      GEN_INT (0)), label);
> +	      if (BB_HEAD (bb) == label)
> +		BB_HEAD (bb) = align;

This is wrong.  As documented, BB_HEAD needs to be either a CODE_LABEL, or
NOTE_INSN_BASIC_BLOCK.
E.g. emit-rtl.cc says
      /* Should not happen as first in the BB is always either NOTE or
         LABEL.  */

	Jakub
H.J. Lu Aug. 12, 2024, 11:19 a.m. UTC | #5
On Mon, Aug 12, 2024 at 12:25 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Thu, Aug 08, 2024 at 06:53:10PM -0700, H.J. Lu wrote:
> > When we emit .p2align to align BB_HEAD, we must update BB_HEAD.  Otherwise
> > ENDBR will be inserted as the wrong place.
> >
> > gcc/
> >
> >       PR target/116174
> >       * config/i386/i386.cc (ix86_align_loops): Update BB_HEAD when
> >       aligning BB_HEAD
> >
> > gcc/testsuite/
> >
> >       PR target/116174
> >       * gcc.target/i386/pr116174.c: New test.
> >
> > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > ---
> >  gcc/config/i386/i386.cc                  |  7 +++++--
> >  gcc/testsuite/gcc.target/i386/pr116174.c | 12 ++++++++++++
> >  2 files changed, 17 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr116174.c
> >
> > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> > index 77c441893b4..ec6cc5e3548 100644
> > --- a/gcc/config/i386/i386.cc
> > +++ b/gcc/config/i386/i386.cc
> > @@ -23528,8 +23528,11 @@ ix86_align_loops ()
> >
> >         if (padding_p && detect_tight_loop_p)
> >           {
> > -           emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> > -                                                 GEN_INT (0)), label);
> > +           rtx_insn *align =
>
> = can't go at the end of line.
>
> > +             emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
> > +                                                   GEN_INT (0)), label);
> > +           if (BB_HEAD (bb) == label)
> > +             BB_HEAD (bb) = align;
>
> This is wrong.  As documented, BB_HEAD needs to be either a CODE_LABEL, or
> NOTE_INSN_BASIC_BLOCK.

ira.cc has

          new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
          REG_NOTES (new_insn) = REG_NOTES (def_insn);
          REG_NOTES (def_insn) = 0;
          /* Rescan it to process the notes.  */
          df_insn_rescan (new_insn);

          /* Make sure this insn is recognized before reload begins,
             otherwise eliminate_regs_in_insn will die.  */
          INSN_CODE (new_insn) = INSN_CODE (def_insn);

          delete_insn (def_insn);

          XEXP (reg_equiv[regno].init_insns, 0) = new_insn;

          REG_BASIC_BLOCK (regno) = use_bb->index;
          REG_N_CALLS_CROSSED (regno) = 0;

          if (use_insn == BB_HEAD (use_bb))
            BB_HEAD (use_bb) = new_insn;

new_insn isn't CODE_LABEL nor NOTE_INSN_BASIC_BLOCK.
Should it be changed?

> E.g. emit-rtl.cc says
>       /* Should not happen as first in the BB is always either NOTE or
>          LABEL.  */
>
>         Jakub
>
Jakub Jelinek Aug. 12, 2024, 11:25 a.m. UTC | #6
On Mon, Aug 12, 2024 at 04:19:58AM -0700, H.J. Lu wrote:
> > This is wrong.  As documented, BB_HEAD needs to be either a CODE_LABEL, or
> > NOTE_INSN_BASIC_BLOCK.
> 
> ira.cc has
> 
>           new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
>           REG_NOTES (new_insn) = REG_NOTES (def_insn);
>           REG_NOTES (def_insn) = 0;
>           /* Rescan it to process the notes.  */
>           df_insn_rescan (new_insn);
> 
>           /* Make sure this insn is recognized before reload begins,
>              otherwise eliminate_regs_in_insn will die.  */
>           INSN_CODE (new_insn) = INSN_CODE (def_insn);
> 
>           delete_insn (def_insn);
> 
>           XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
> 
>           REG_BASIC_BLOCK (regno) = use_bb->index;
>           REG_N_CALLS_CROSSED (regno) = 0;
> 
>           if (use_insn == BB_HEAD (use_bb))
>             BB_HEAD (use_bb) = new_insn;
> 
> new_insn isn't CODE_LABEL nor NOTE_INSN_BASIC_BLOCK.
> Should it be changed?

Guess it depends if it survives that way until after the pass or not, if
the pass can tolerate temporary violation, fine, if it survives to next
passes, it is not.

	Jakub
H.J. Lu Aug. 12, 2024, 11:30 a.m. UTC | #7
On Mon, Aug 12, 2024 at 4:25 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Mon, Aug 12, 2024 at 04:19:58AM -0700, H.J. Lu wrote:
> > > This is wrong.  As documented, BB_HEAD needs to be either a CODE_LABEL, or
> > > NOTE_INSN_BASIC_BLOCK.
> >
> > ira.cc has
> >
> >           new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
> >           REG_NOTES (new_insn) = REG_NOTES (def_insn);
> >           REG_NOTES (def_insn) = 0;
> >           /* Rescan it to process the notes.  */
> >           df_insn_rescan (new_insn);
> >
> >           /* Make sure this insn is recognized before reload begins,
> >              otherwise eliminate_regs_in_insn will die.  */
> >           INSN_CODE (new_insn) = INSN_CODE (def_insn);
> >
> >           delete_insn (def_insn);
> >
> >           XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
> >
> >           REG_BASIC_BLOCK (regno) = use_bb->index;
> >           REG_N_CALLS_CROSSED (regno) = 0;
> >
> >           if (use_insn == BB_HEAD (use_bb))
> >             BB_HEAD (use_bb) = new_insn;
> >
> > new_insn isn't CODE_LABEL nor NOTE_INSN_BASIC_BLOCK.
> > Should it be changed?
>
> Guess it depends if it survives that way until after the pass or not, if
> the pass can tolerate temporary violation, fine, if it survives to next
> passes, it is not.

I assume that the IRA code is triggered and works.
Richard Sandiford Aug. 12, 2024, 7:38 p.m. UTC | #8
"H.J. Lu" <hjl.tools@gmail.com> writes:
> On Mon, Aug 12, 2024 at 4:25 AM Jakub Jelinek <jakub@redhat.com> wrote:
>>
>> On Mon, Aug 12, 2024 at 04:19:58AM -0700, H.J. Lu wrote:
>> > > This is wrong.  As documented, BB_HEAD needs to be either a CODE_LABEL, or
>> > > NOTE_INSN_BASIC_BLOCK.
>> >
>> > ira.cc has
>> >
>> >           new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
>> >           REG_NOTES (new_insn) = REG_NOTES (def_insn);
>> >           REG_NOTES (def_insn) = 0;
>> >           /* Rescan it to process the notes.  */
>> >           df_insn_rescan (new_insn);
>> >
>> >           /* Make sure this insn is recognized before reload begins,
>> >              otherwise eliminate_regs_in_insn will die.  */
>> >           INSN_CODE (new_insn) = INSN_CODE (def_insn);
>> >
>> >           delete_insn (def_insn);
>> >
>> >           XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
>> >
>> >           REG_BASIC_BLOCK (regno) = use_bb->index;
>> >           REG_N_CALLS_CROSSED (regno) = 0;
>> >
>> >           if (use_insn == BB_HEAD (use_bb))
>> >             BB_HEAD (use_bb) = new_insn;
>> >
>> > new_insn isn't CODE_LABEL nor NOTE_INSN_BASIC_BLOCK.
>> > Should it be changed?
>>
>> Guess it depends if it survives that way until after the pass or not, if
>> the pass can tolerate temporary violation, fine, if it survives to next
>> passes, it is not.
>
> I assume that the IRA code is triggered and works.

Looks like it might be a left-over.  The code was originally added to
local-alloc.c by r0-13022-g2e1253f38590:

commit 2e1253f38590eb4bd47b3635e0f04c28423764d0 (HEAD)
Author: Ian Lance Taylor <ian@gcc.gnu.org>
Date:   Fri Jan 31 22:09:12 1997 +0000

    If we can't substitute an equiv reg only used once, move the
    assignment

which unfortunately predates the current list archives.  But at the
time, there were no basic block notes in the current sense.  Instead,
NOTE_INSN_BLOCK_BEG/END were only emitted by stmt.c (i.e. during expand),
and AFAICT marked the boundaries of source language blocks.  The basic
blocks constructed by flow could start with any instruction:

      /* A basic block starts at label, or after something that can jump.  */
      else if (code == CODE_LABEL
	       || (GET_RTX_CLASS (code) == 'i'
		   && (prev_code == JUMP_INSN
		       || (prev_code == CALL_INSN
			   && nonlocal_label_list != 0
			   && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
		       || prev_code == BARRIER)))
	{
	  basic_block_head[++i] = insn;

Combine also had similar code:

		  /* If this insn was emitted between blocks, then update
		     basic_block_head of the current block to include it.  */
		  if (basic_block_end[this_basic_block - 1] == tem)
		    basic_block_head[this_basic_block] = place;

but that was removed in r0-24369-gd3a923ee2e1.

Thanks,
Richard
diff mbox series

Patch

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 77c441893b4..ec6cc5e3548 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -23528,8 +23528,11 @@  ix86_align_loops ()
 
 	  if (padding_p && detect_tight_loop_p)
 	    {
-	      emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
-						    GEN_INT (0)), label);
+	      rtx_insn *align =
+		emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
+						      GEN_INT (0)), label);
+	      if (BB_HEAD (bb) == label)
+		BB_HEAD (bb) = align;
 	      /* End of function.  */
 	      if (!tbb || tbb == EXIT_BLOCK_PTR_FOR_FN (cfun))
 		break;
diff --git a/gcc/testsuite/gcc.target/i386/pr116174.c b/gcc/testsuite/gcc.target/i386/pr116174.c
new file mode 100644
index 00000000000..8877d0b51af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr116174.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fcf-protection=branch" } */
+
+char *
+foo (char *dest, const char *src)
+{
+  while ((*dest++ = *src++) != '\0')
+    /* nothing */;
+  return --dest;
+}
+
+/* { dg-final { scan-assembler "\t\.cfi_startproc\n\tendbr(32|64)\n" } } */