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.

[ 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.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Signed-off-by: Kyrylo Tkachov <[email protected]>
Signed-off-by: Uros Bizjak <[email protected]>

Uros.
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;
+}

Reply via email to