Hi!

The committed __builtin_bitreverse* patch mishandled the
bitwise CCP handling, it is true that BUILT_IN_BITREVERSE* can be
handled there similarly to BUILT_IN_BSWAP*, but not exactly, for
the latter we need (and do) bswap the value and mask constants,
while for the former we obviously need to bitreverse them instead.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-05-16  Jakub Jelinek  <[email protected]>

        PR target/50481
        * tree-ssa-ccp.cc (evaluate_stmt): Fix up
        BUILT_IN_BITREVERSE{8,16,32,64} handling.

        * gcc.dg/builtin-bitreverse-3.c: New test.

--- gcc/tree-ssa-ccp.cc.jj      2026-05-15 22:26:46.621857908 +0200
+++ gcc/tree-ssa-ccp.cc 2026-05-16 10:21:46.786421477 +0200
@@ -2435,10 +2435,6 @@ evaluate_stmt (gimple *stmt)
            case BUILT_IN_BSWAP32:
            case BUILT_IN_BSWAP64:
            case BUILT_IN_BSWAP128:
-           case BUILT_IN_BITREVERSE8:
-           case BUILT_IN_BITREVERSE16:
-           case BUILT_IN_BITREVERSE32:
-           case BUILT_IN_BITREVERSE64:
              val = get_value_for_expr (gimple_call_arg (stmt, 0), true);
              if (val.lattice_val == UNDEFINED)
                break;
@@ -2461,6 +2457,33 @@ evaluate_stmt (gimple *stmt)
                  if (wi::sext (val.mask, prec) != -1)
                    break;
                }
+             val.lattice_val = VARYING;
+             val.value = NULL_TREE;
+             val.mask = -1;
+             break;
+
+           case BUILT_IN_BITREVERSE8:
+           case BUILT_IN_BITREVERSE16:
+           case BUILT_IN_BITREVERSE32:
+           case BUILT_IN_BITREVERSE64:
+             val = get_value_for_expr (gimple_call_arg (stmt, 0), true);
+             if (val.lattice_val == UNDEFINED)
+               break;
+             else if (val.lattice_val == CONSTANT
+                      && val.value
+                      && TREE_CODE (val.value) == INTEGER_CST)
+               {
+                 tree type = TREE_TYPE (gimple_call_lhs (stmt));
+                 int prec = TYPE_PRECISION (type);
+                 wide_int wval = wi::to_wide (val.value);
+                 wval = wide_int::from (wval, prec, UNSIGNED);
+                 wide_int wmask = wide_int::from (val.mask, prec, UNSIGNED);
+                 val.value = wide_int_to_tree (type, wi::bitreverse (wval));
+                 val.mask = widest_int::from (wi::bitreverse (wmask),
+                                              UNSIGNED);
+                 if (wi::sext (val.mask, prec) != -1)
+                   break;
+               }
              val.lattice_val = VARYING;
              val.value = NULL_TREE;
              val.mask = -1;
--- gcc/testsuite/gcc.dg/builtin-bitreverse-3.c.jj      2026-03-27 
08:35:17.031535967 +0100
+++ gcc/testsuite/gcc.dg/builtin-bitreverse-3.c 2026-05-16 10:18:41.063664634 
+0200
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#if __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+[[gnu::noipa]] bool
+foo (unsigned x)
+{
+  x &= 0x499a750a;
+  x |= 0x5a7c04f;
+  x = __builtin_bitreverse32 (x);
+  return (x & ~0x351848) == 0x4fc0a705;
+}
+
+[[gnu::noipa]] bool
+bar (unsigned x)
+{
+  x &= 0x499a750a;
+  x |= 0x5a7c04f;
+  x = __builtin_bitreverse32 (x);
+  return (x & ~0xac1812) == 0xf203e5a0;
+}
+#endif
+
+int
+main ()
+{
+#if __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+  if (foo (~0) || !bar (~0))
+    __builtin_abort ();
+#endif
+}

        Jakub

Reply via email to