The backward jump threader fails to thread the state-machine loop in
binascii_a2b_base64 because the switch has already been lowered to a
decision tree by the time the late FSM threading runs, and the
duplication limits are tight for the resulting branch sequence.

Move the switch lowering after the backward jump threader so it still
sees the GIMPLE_SWITCH.  pass_dominator and pass_strlen keep their
place relative to the jump threaders, so the only change is the
position of pass_lower_switch.  This restores the GCC 11 performance
for the state machine in PR128102.

gcc/
        * passes.def (pass_lower_switch): Move after pass_thread_jumps_full.

gcc/testsuite/
        * gcc.dg/tree-ssa/pr128102.c: New test.
---
 gcc/passes.def                           |  4 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr128102.c | 69 ++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr128102.c

diff --git a/gcc/passes.def b/gcc/passes.def
index 9095c134f49..64b8f8102d2 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -346,7 +346,6 @@ along with GCC; see the file COPYING3.  If not see
       POP_INSERT_PASSES ()
       NEXT_PASS (pass_simduid_cleanup);
       NEXT_PASS (pass_lower_vector_ssa);
-      NEXT_PASS (pass_lower_switch);
       NEXT_PASS (pass_cse_sincos);
       NEXT_PASS (pass_cse_reciprocals);
       NEXT_PASS (pass_reassoc, false /* early_p */);
@@ -355,10 +354,13 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_fre, false /* may_iterate */);
       /* After late FRE we rewrite no longer addressed locals into SSA
          form if possible.  */
+      /* Thread the loop with the backward threader before lowering
+        switches so it still sees the GIMPLE_SWITCH.  */
       NEXT_PASS (pass_thread_jumps, /*first=*/false);
       NEXT_PASS (pass_dominator, false /* may_peel_loop_headers_p */);
       NEXT_PASS (pass_strlen);
       NEXT_PASS (pass_thread_jumps_full, /*first=*/false);
+      NEXT_PASS (pass_lower_switch);
       NEXT_PASS (pass_vrp, true /* final_p */);
       /* Run CCP to compute alignment and nonzero bits.  */
       NEXT_PASS (pass_ccp, true /* nonzero_p */);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr128102.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr128102.c
new file mode 100644
index 00000000000..29374fc3a73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr128102.c
@@ -0,0 +1,69 @@
+/* PR tree-optimization/128102 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef unsigned char u8;
+
+static u8 table_a2b_base64[256];
+
+__attribute__ ((noinline, noclone)) size_t
+decode_b64 (const u8 *restrict src, size_t len, u8 *restrict dst)
+{
+  u8 *out = dst;
+  int quad_pos = 0;
+  u8 leftchar = 0;
+
+  for (size_t i = 0; i < len; i++)
+    {
+      u8 this_ch = src[i];
+
+      if (this_ch == '=')
+       continue;
+
+      this_ch = table_a2b_base64[this_ch];
+      if (this_ch >= 64)
+       continue;
+
+      switch (quad_pos)
+       {
+       case 0:
+         quad_pos = 1;
+         leftchar = this_ch;
+         break;
+       case 1:
+         quad_pos = 2;
+         *out++ = (u8) ((leftchar << 2) | (this_ch >> 4));
+         leftchar = this_ch & 0x0f;
+         break;
+       case 2:
+         quad_pos = 3;
+         *out++ = (u8) ((leftchar << 4) | (this_ch >> 2));
+         leftchar = this_ch & 0x03;
+         break;
+       case 3:
+         quad_pos = 0;
+         *out++ = (u8) ((leftchar << 6) | this_ch);
+         leftchar = 0;
+         break;
+       }
+    }
+  return (size_t) (out - dst);
+}
+
+int
+main (void)
+{
+  static u8 src[256], dst[256];
+
+  for (int i = 0; i < 256; i++)
+    table_a2b_base64[i] = (u8) (i & 63);
+
+  return (int) decode_b64 (src, sizeof src, dst);
+}
+
+/* Threading the loop back edge replicates the loop body, and quad_pos
+   becomes a constant on every copy, so the '=' test of the source loop
+   is left 11 times.  Without the fix the loop stays rolled and the test
+   appears only once.  */
+/* { dg-final { scan-tree-dump-times "== 61" 11 "optimized" } } */
-- 
2.34.1

Reply via email to