]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PATCH] match.pd: make "if (c) a |= CST1 else a &= ~CST1" unconditional [PR123967]
authorDaniel Barboza <daniel.barboza@oss.qualcomm.com>
Fri, 1 May 2026 20:53:12 +0000 (14:53 -0600)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Fri, 1 May 2026 21:33:32 +0000 (15:33 -0600)
We have an instance in Perlbench of a code that if a condition is true a
bit is set, if false the same bit is cleared.  This can be made
unconditional by always running the bit clear, and then run the bit_ior
with the result of (cond) * CST1:

(a & ~CST1) | (cond * CST1)

If "cond" is false (zero) the bit_ior is a no-op and the bit will remain
cleared, if "cond" is true we'll set the bit as intended.

Note that the transformation will add a mult into the pattern, therefore
make it valid only if type <= word_size to avoid wide int
multiplications.

Bootstrapped on x86, aarch64 and rv64.
Regression tested on x86 and aarch64.

PR rtl-optimization/123967

gcc/ChangeLog:

* match.pd(`if (cond) (A | CST1) : (A & ~CST1)`)`: New pattern.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr123967-2.c: New test.
* gcc.dg/tree-ssa/pr123967-3.c: New test.
* gcc.dg/tree-ssa/pr123967.c: New test.

gcc/match.pd
gcc/testsuite/gcc.dg/tree-ssa/pr123967-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr123967-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr123967.c [new file with mode: 0644]

index 9e450f3985fbe1914f95ab7d60d8f9458c393aca..3cf07123e716755256f05600ad01c409ddb50fb9 100644 (file)
@@ -6777,6 +6777,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && INTEGRAL_TYPE_P (TREE_TYPE (@0)))
   (cond @1 (convert @2) (convert @3))))
 
+/* PR123967: if (cond) A | CST1 : A & ~CST1
+
+   Make both bitops unconditional: (A & ~CST1) | (cond * CST1).  */
+(for cmp (simple_comparison)
+ (simplify
+  (cond (cmp@4 @5 @6) (bit_ior @0 INTEGER_CST@1) (bit_and@3 @0 INTEGER_CST@2))
+   (if (INTEGRAL_TYPE_P (type)
+       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && (TYPE_UNSIGNED (TREE_TYPE (@1)) || tree_int_cst_sgn (@1) > 0)
+       && TYPE_PRECISION (type) <= BITS_PER_WORD
+       && wi::to_wide (@1) == ~wi::to_wide (@2))
+    (bit_ior @3 (mult (convert:type @4) (convert:type @1))))))
+
 /* Simplification moved from fold_cond_expr_with_comparison.  It may also
    be extended.  */
 /* This pattern implements two kinds simplification:
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr123967-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr123967-2.c
new file mode 100644 (file)
index 0000000..5abef93
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-additional-options -O2 } */
+/* { dg-additional-options -fdump-tree-optimized } */
+
+unsigned f1 (unsigned x, unsigned m)
+{
+  if (x)
+    m |= 0x3;
+  else
+    m = m & ~0x3;
+
+  return m + 1;
+}
+
+unsigned f2 (unsigned x, int m)
+{
+  int mask = 0x3;
+
+  if (x)
+    m |= mask;
+  else
+    m = m & ~mask;
+
+  return m + 1;
+}
+/* { dg-final { scan-tree-dump-times " \\\| 3" 0 optimized } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr123967-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr123967-3.c
new file mode 100644 (file)
index 0000000..935a4e2
--- /dev/null
@@ -0,0 +1,48 @@
+/* { dg-do run } */
+/* { dg-additional-options -O2 } */
+
+void abort(void);
+
+/* Macro adapted from builtin-object-size-common.h  */
+#define FAIL() \
+  do { \
+    __builtin_printf ("Failure at line: %d\n", __LINE__);     \
+    abort();                                                 \
+  } while (0)
+
+unsigned f1 (unsigned x, int m)
+{
+  int mask = 0x3;
+
+  if (x)
+    m |= mask;
+  else
+    m = m & ~mask;
+
+  return m + 1;
+}
+
+unsigned f2 (unsigned x, int m)
+{
+  if (x)
+    m |= 0x3;
+  else
+    m = m & ~0x8;
+
+  return m + 1;
+}
+
+int main (void)
+{
+  if (f1 (0, 7) != 5)
+    FAIL ();
+  if (f1 (1, 7) != 8)
+    FAIL ();
+
+  if (f2 (0, 8) != 1)
+    FAIL ();
+  if (f2 (1, 8) != 12)
+    FAIL ();    
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr123967.c b/gcc/testsuite/gcc.dg/tree-ssa/pr123967.c
new file mode 100644 (file)
index 0000000..45459ce
--- /dev/null
@@ -0,0 +1,97 @@
+/* { dg-additional-options -O2 } */
+/* { dg-additional-options -fdump-tree-optimized } */
+
+/* Code taken from Perlbench */
+
+typedef long unsigned int size_t;
+typedef long int ssize_t;
+typedef size_t STRLEN;
+typedef struct cop COP;
+typedef struct sv SV;
+typedef struct p5rx REGEXP;
+typedef struct magic MAGIC;
+typedef unsigned char U8;
+typedef int I32;
+typedef unsigned int U32;
+
+typedef int boolean;
+
+struct sv
+{
+  void *sv_any;
+  U32 sv_flags;
+  union
+  {
+    SV *svu_rv;
+  } sv_u;
+};
+struct p5rx
+{
+  union
+  {
+    struct regexp *svu_rx;
+  } sv_u;
+};
+typedef struct regexp
+{
+  U32 extflags;
+} regexp;
+typedef struct
+{
+  char *ganch;
+} regmatch_info;
+struct cop
+{
+  U32 cop_hints;
+};
+struct magic
+{
+  U8 mg_flags;
+  ssize_t mg_len;
+};
+MAGIC *Perl_mg_find_mglob (SV * sv);
+extern COP *PL_curcop;
+extern STRLEN S_MgBYTEPOS (MAGIC *mg, SV *sv, const char *s, STRLEN len) ;
+
+static struct regexp *
+S_ReANY (const REGEXP *const re)
+{
+  return re->sv_u.svu_rx;
+}
+
+
+I32
+Perl_regexec_flags (REGEXP *const rx, char *stringarg, char *strend,
+                    char *strbeg, ssize_t minend, SV *sv, void *data,
+                    U32 flags)
+{
+  char *startpos;
+  ssize_t minlen;
+  MAGIC *mg;
+
+  const boolean
+    utf8_target =
+    (((((sv)->sv_flags & 0x20000000)
+       && !(((PL_curcop)->cop_hints + 0) & 0x00000008))) ? 1 : 0);
+  regmatch_info reginfo_buf;
+  regmatch_info *const reginfo = &reginfo_buf;
+
+  startpos = stringarg;
+
+  reginfo->ganch =
+    (flags & 0x08)
+    ? stringarg
+    : ((mg = Perl_mg_find_mglob (sv)) && mg->mg_len >= 0)
+    ? strbeg + S_MgBYTEPOS (mg, sv, strbeg, strend - strbeg) : strbeg;
+
+  if ((startpos + minlen) > strend || startpos < strbeg)
+      return 0;
+
+  ((utf8_target)
+   ? (((S_ReANY ((const REGEXP *) (rx)))->extflags) |=
+      (1U << (((0 + 12) + 2) + 6)))
+   : (((S_ReANY ((const REGEXP *) (rx)))->extflags) &=
+      ~(1U << (((0 + 12) + 2) + 6))));
+
+}
+/* { dg-final { scan-tree-dump-times " \\\| 1048576" 0 optimized } } */