On Wed, Sep 23, 2026 at 2:41 PM Uros Bizjak <[email protected]> wrote:
>
> On Wed, Sep 23, 2026 at 10:44 AM Uros Bizjak <[email protected]> wrote:
> >
> > On Wed, Sep 23, 2026 at 10:20 AM Kyrylo Tkachov <[email protected]> wrote:
> > >
> > >
> > >
> > > > On 23 Sep 2026, at 10:04, Uros Bizjak <[email protected]> wrote:
> > > >
> > > > On Wed, Sep 23, 2026 at 8:45 AM Hongtao Liu <[email protected]> wrote:
> > > >>
> > > >> On Tue Sep 22, 2026 at 3:07 AM PDT, Uros Bizjak wrote:
> > > >>> On Tue, Sep 22, 2026 at 11:34 AM <[email protected]> wrote:
> > > >>>>
> > > >>>> From: Kyrylo Tkachov <[email protected]>
> > > >>>>
> > > >>>> Different switch tables can reach the same case block. The CET pass
> > > >>>> inserts an ENDBR for each table, although the destination needs only 
> > > >>>> one.
> > > >>>> This also affects dispatches that share a table.
> > > >>>>
> > > >>>> Reuse an existing ENDBR after the destination label. The x86 
> > > >>>> table-sharing
> > > >>>> hook remains disabled.
> > > >>>>
> > > >>>> The regression test has two ordinary tables with eight common 
> > > >>>> destinations.
> > > >>>> It emits 17 ENDBR instructions before the fix and 9 after it, in both
> > > >>>> 32-bit and 64-bit code. Both outputs assemble. A 64-bit runtime check
> > > >>>> passes on x86_64.
> > > >>>>
> > > >>>> This patch was written by an AI agent as I'm not familiar enough with
> > > >>>> the x86 internals and can't vouch for it. But if the x86 maintainers
> > > >>>> want it I'm happy to push it.
> > > >>>>
> > > >>>> Assisted-by: OpenAI Codex 5.6 Sol
> > > >>>>
> > > >>>> gcc/ChangeLog:
> > > >>>>
> > > >>>>        * config/i386/i386-features.cc
> > > >>>>        (rest_of_insert_endbr_and_patchable_area): Reuse an existing
> > > >>>>        ENDBR at a switch destination.
> > > >>>>
> > > >>>> gcc/testsuite/ChangeLog:
> > > >>>>
> > > >>>>        * gcc.target/i386/cet-switch-4.c: New test.
> > > >>>>
> > > >>>> Cc: Uros Bizjak <[email protected]>
> > > >>>> Signed-off-by: Kyrylo Tkachov <[email protected]>
> > > >>>> ---
> > > >>>> gcc/config/i386/i386-features.cc             |  4 ++
> > > >>>> gcc/testsuite/gcc.target/i386/cet-switch-4.c | 56 
> > > >>>> ++++++++++++++++++++
> > > >>>> 2 files changed, 60 insertions(+)
> > > >>>> create mode 100644 gcc/testsuite/gcc.target/i386/cet-switch-4.c
> > > >>>>
> > > >>>> diff --git a/gcc/config/i386/i386-features.cc 
> > > >>>> b/gcc/config/i386/i386-features.cc
> > > >>>> index 1d26aa0c336..7c992eadf3c 100644
> > > >>>> --- a/gcc/config/i386/i386-features.cc
> > > >>>> +++ b/gcc/config/i386/i386-features.cc
> > > >>>> @@ -3274,6 +3274,10 @@ rest_of_insert_endbr_and_patchable_area (bool 
> > > >>>> need_endbr,
> > > >>>>                  dest_blk = e->dest;
> > > >>>>                  insn = BB_HEAD (dest_blk);
> > > >>>>                  gcc_assert (LABEL_P (insn));
> > > >>>> +                 rtx_insn *next = next_nonnote_nondebug_insn (insn);
> > > >>>> +                 if (next && INSN_P (next)
> > > >>>> +                     && recog_memoized (next) == CODE_FOR_nop_endbr)
> > > >>>
> > > >>> The condition should read:
> > > >>>
> > > >>> if (next && NONJUMP_INSN_P (next)
> > > >> NONDEBUG_INSN_P (next)?
> > > >
> > > > next is found with:
> > > >
> > > > rtx_insn *next = next_nonnote_nondebug_insn (insn);
> > > >
> > > > so we are sure we are dealing with nondebug insn.
> > > >
> > >
> > > Can one of the i386 maintainers take this up and push a version you’re 
> > > happy with, please?
> >
> > I'll do it.
>
> Please check the attached patch, if it fixes your issue.

Oh, I attached the wrong version, this is the correct one.

Uros.
From 690f9489227543fac955e9909871a4e665b9ca2d Mon Sep 17 00:00:00 2001
From: Kyrylo Tkachov <[email protected]>
Date: Tue, 22 Sep 2026 11:33:26 +0200
Subject: [PATCH] i386: Avoid duplicate ENDBR

Different switch tables can reach the same case block. The CET pass
inserts an ENDBR for each table, although the destination needs only one.
This also affects dispatches that share a table.

Reuse an existing ENDBR after the destination label.

[ ubizjak: Use GET_CODE/XINT, adjust ChangeLog ]

gcc/ChangeLog:

	* config/i386/i386-features.cc
	(rest_of_insert_endbr_and_patchable_area):
	Reuse an existing ENDBR.

gcc/testsuite/ChangeLog:

	* gcc.target/i386/cet-switch-4.c: New test.

Assisted-by: OpenAI Codex 5.6 Sol
Signed-off-by: Kyrylo Tkachov <[email protected]>
Signed-off-by: Uros Bizjak <[email protected]>
---
 gcc/config/i386/i386-features.cc             |  8 +++
 gcc/testsuite/gcc.target/i386/cet-switch-4.c | 56 ++++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/cet-switch-4.c

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 1d26aa0c336..f95bc41fb47 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -3274,6 +3274,14 @@ rest_of_insert_endbr_and_patchable_area (bool need_endbr,
 		  dest_blk = e->dest;
 		  insn = BB_HEAD (dest_blk);
 		  gcc_assert (LABEL_P (insn));
+
+		  /* Reuse existing ENDBR.  */
+		  rtx_insn *next = next_nonnote_nondebug_insn (insn);
+		  if (next && NONJUMP_INSN_P (next)
+		      && GET_CODE (PATTERN (next)) == UNSPEC_VOLATILE
+		      && XINT (PATTERN (next), 1) == UNSPECV_NOP_ENDBR)
+		    continue;
+
 		  endbr = gen_nop_endbr ();
 		  emit_insn_after (endbr, insn);
 		}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-4.c b/gcc/testsuite/gcc.target/i386/cet-switch-4.c
new file mode 100644
index 00000000000..53cb960f0d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-4.c
@@ -0,0 +1,56 @@
+/* PR middle-end/126236 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection=branch -mcet-switch -fno-pie -fno-pic" } */
+/* { dg-final { scan-assembler-times "endbr32" 9 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 9 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "\[ \t]+jmp\[ \t]+\[*]" 2 } } */
+
+/* Both tables reach the same eight destinations.  */
+
+void f0 (void);
+void f1 (void);
+void f2 (void);
+void f3 (void);
+void f4 (void);
+void f5 (void);
+void f6 (void);
+void f7 (void);
+
+void
+foo (unsigned x, int which)
+{
+  if (which)
+    switch (x)
+      {
+      case 0: goto a;
+      case 1: goto b;
+      case 2: goto c;
+      case 3: goto d;
+      case 4: goto e;
+      case 5: goto f;
+      case 6: goto g;
+      case 7: goto h;
+      default: return;
+      }
+  else
+    switch (x)
+      {
+      case 0: goto h;
+      case 1: goto g;
+      case 2: goto f;
+      case 3: goto e;
+      case 4: goto d;
+      case 5: goto c;
+      case 6: goto b;
+      case 7: goto a;
+      default: return;
+      }
+a: f0 (); return;
+b: f1 (); return;
+c: f2 (); return;
+d: f3 (); return;
+e: f4 (); return;
+f: f5 (); return;
+g: f6 (); return;
+h: f7 (); return;
+}
-- 
2.55.0

Reply via email to