https://gcc.gnu.org/g:65f27f5a1562300f72b0fe8cfd65e7901f528763

commit r17-4624-g65f27f5a1562300f72b0fe8cfd65e7901f528763
Author: Kyrylo Tkachov <[email protected]>
Date:   Tue Sep 22 11:33:26 2026 +0200

    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 ]
    
    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.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/i386/cet-switch-4.c: New test.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>
    Signed-off-by: Uros Bizjak <[email protected]>

Diff:
---
 gcc/config/i386/i386-features.cc             |  8 ++++
 gcc/testsuite/gcc.target/i386/cet-switch-4.c | 56 ++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 1d26aa0c3362..f95bc41fb479 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 000000000000..53cb960f0d56
--- /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;
+}

Reply via email to