[v3] simplify-rtx: Simplify (op (and/ior x C1) C2) in special cases

Message ID 20260408033626.36165-1-garthlei@linux.alibaba.com
State New
Headers
Series [v3] simplify-rtx: Simplify (op (and/ior x C1) C2) in special cases |

Checks

Context Check Description
rivoscibot/toolchain-ci-rivos-apply-patch success Patch applied
rivoscibot/toolchain-ci-rivos-lint warning Lint failed
rivoscibot/toolchain-ci-rivos-build--newlib-rv64gcv-lp64d-multilib success Build passed
rivoscibot/toolchain-ci-rivos-build--linux-rv64gcv-lp64d-multilib success Build passed
rivoscibot/toolchain-ci-rivos-build--linux-rv64gc_zba_zbb_zbc_zbs-lp64d-multilib success Build passed
rivoscibot/toolchain-ci-rivos-test success Testing passed

Commit Message

Bohan Lei April 8, 2026, 3:36 a.m. UTC
  This is v3 of
https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711809.html, fixed
and enhanced as was suggested by Philipp and Andrew.  The previous
version:
https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711833.html.

This patch adds missing simplifications for (op (and/ior x C1) C2) in
special cases.  In the AND case, when (and C1 C2) is not equal to C1,
some bits set in C2 are not set in C1, and thus (eq (and x C1) C2) can
never be true.  The OR case is similar when (and C1 C2) is not equal to
C2.  As we know that the result of (and x C1) cannot be greater than C1,
and that that of (or x C1) cannot be less than C1 for unsigned integers,
LTU, LEU, GTU, GEU cases can be optimized, too.

The patch is meant to fix an ICE on RISC-V.  In a former patch, I tried
to change the insn condition directly, but Jeff pointed out that it was
more reasonable to optimize it out before the split.  As was suggested
by Jeff, this patch tries to simplify the expression in
simplify_relational_operation_1.

The URL for the former patch:
https://patchwork.sourceware.org/project/gcc/patch/20251229024238.15044-1-garthlei@linux.alibaba.com/

gcc/ChangeLog:

	* simplify-rtx.cc (simplify_context::simplify_relational_operation_1):
Add simplifications for (op (and/ior x C1) C2) in special cases.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zbs-if_then_else-02.c: New test.
---
 gcc/simplify-rtx.cc                           | 45 +++++++++++++++++++
 .../gcc.target/riscv/zbs-if_then_else-02.c    | 32 +++++++++++++
 2 files changed, 77 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
  

Comments

Andrew Pinski April 10, 2026, 2:34 a.m. UTC | #1
On Tue, Apr 7, 2026 at 8:36 PM Bohan Lei <garthlei@linux.alibaba.com> wrote:
>
> This is v3 of
> https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711809.html, fixed
> and enhanced as was suggested by Philipp and Andrew.  The previous
> version:
> https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711833.html.
>
> This patch adds missing simplifications for (op (and/ior x C1) C2) in
> special cases.  In the AND case, when (and C1 C2) is not equal to C1,
> some bits set in C2 are not set in C1, and thus (eq (and x C1) C2) can
> never be true.  The OR case is similar when (and C1 C2) is not equal to
> C2.  As we know that the result of (and x C1) cannot be greater than C1,
> and that that of (or x C1) cannot be less than C1 for unsigned integers,
> LTU, LEU, GTU, GEU cases can be optimized, too.
>
> The patch is meant to fix an ICE on RISC-V.  In a former patch, I tried
> to change the insn condition directly, but Jeff pointed out that it was
> more reasonable to optimize it out before the split.  As was suggested
> by Jeff, this patch tries to simplify the expression in
> simplify_relational_operation_1.
>
> The URL for the former patch:
> https://patchwork.sourceware.org/project/gcc/patch/20251229024238.15044-1-garthlei@linux.alibaba.com/
>
> gcc/ChangeLog:
>
>         * simplify-rtx.cc (simplify_context::simplify_relational_operation_1):
> Add simplifications for (op (and/ior x C1) C2) in special cases.

There seems to be some incorrect wrapping of the changelog going on.
it should be (with a tab in front of each line):
* simplify-rtx.cc (simplify_context::simplify_relational_operation_1): Add
 simplifications for `(cmp (and/ior x C1) C2)`.

Note I changed op to cmp to specify that the op is a comparison; it
makes it quicker
to read the changelog and see it only handles comparisons here (even
though the change
is in relational_operation which is for comparisons).

>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/riscv/zbs-if_then_else-02.c: New test.
> ---
>  gcc/simplify-rtx.cc                           | 45 +++++++++++++++++++
>  .../gcc.target/riscv/zbs-if_then_else-02.c    | 32 +++++++++++++
>  2 files changed, 77 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
>
> diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
> index 50fc51152ca..eeabcb4af6f 100644
> --- a/gcc/simplify-rtx.cc
> +++ b/gcc/simplify-rtx.cc
> @@ -6731,6 +6731,51 @@ simplify_context::simplify_relational_operation_1 (rtx_code code,
>         }
>      }
>
> +  /* Several optimizable scenerios of (op (and/ior x C1) C2) */
I think it would be better worded as:
/* Optimize (cmp (and/ior x C1) C2)  depending on the CMP and C1 and
C2's relationship.  */


> +  if ((op0code == AND || op0code == IOR)
> +      && CONST_INT_P (op1)
> +      && CONST_INT_P (XEXP (op0, 1)))
> +    {
> +      unsigned HOST_WIDE_INT c1 = UINTVAL (XEXP (op0, 1));
> +      unsigned HOST_WIDE_INT c2 = UINTVAL (op1);
> +
> +      /* For AND operations:
> +          - (x & c1) == c2 when some bits are set in c2 but not in c1 -> false
> +          - (x & c1) != c2 when some bits are set in c2 but not in c1 -> true
> +          - (x & c1) >= c2 when c1 is less than c2 -> false
> +          - (x & c1) < c2 when c1 is less than c2 -> true
> +          - (x & c1) > c2 when c1 is less than or equal to c2 -> false
> +          - (x & c1) <= c2 when c1 is less than or equal to c2 -> true
> +
> +        For IOR operations:
> +          - (x | c1) == c2 when some bits are set in c1 but not in c2 -> false
> +          - (x | c1) != c2 when some bits are set in c1 but not in c2 -> true
> +          - (x | c1) <= c2 when c1 is greater than c2 -> false
> +          - (x | c1) > c2 when c1 is greater than c2 -> true
> +          - (x | c1) < c2 when c1 is greater than or equal to c2 -> false
> +          - (x | c1) >= c2 when c1 is greater than or equal to c2 -> true */
> +      if ((op0code == AND
> +          && ((code == EQ && (c1 & c2) != c2)
> +              || (code == GEU && c1 < c2)
> +              || (code == GTU && c1 <= c2)))
> +         || ((op0code == IOR
> +             && ((code == EQ && (c1 & c2) != c1)
> +                 || (code == LEU && c1 > c2)
> +                 || (code == LTU && c1 >= c2)))))
> +       return const0_rtx;
> +
> +

Extra return.

> +      if ((op0code == AND
> +          && ((code == NE && (c1 & c2) != c2)
> +              || (code == LTU && c1 < c2)
> +              || (code == LEU && c1 <= c2)))
> +         || ((op0code == IOR
> +             && ((code == NE && (c1 & c2) != c1)
> +                 || (code == GTU && c1 > c2)
> +                 || (code == GEU && c1 >= c2)))))
> +       return const_true_rtx;
> +    }
> +

Otherwise ok for stage1.

Thanks,
Andrew

>    /* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped.  */
>    if ((code == EQ || code == NE)
>        && GET_CODE (op0) == BSWAP
> diff --git a/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c b/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
> new file mode 100644
> index 00000000000..3393bea8898
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
> @@ -0,0 +1,32 @@
> +/* { dg-do link  { target { rv64 } } } */
> +/* { dg-options "-march=rv64gc_zbb_zbs -mabi=lp64d -flto" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */
> +
> +struct S {
> +  int a;
> +  char b;
> +  int c;
> +} s;
> +
> +const signed char c = -37;
> +int d;
> +struct S v1[] = {{0, 8}, 0, 0, -108976}, v2[] = {{}, 0, 0, 2804};
> +int a;
> +struct S v3[3];
> +int *p = &a;
> +
> +void foo() {
> +  int a;
> +  if (a)
> +    ;
> +  else if (v1[0].b)
> +    s.a = 0;
> +  else
> +    d = 0;
> +  if (*p)
> +    if (v3[1].c)
> +      if (1 ^ (d & c & v2[1].c & ~v1[1].c | s.a))
> +        v3[2].c = 0;
> +}
> +
> +int main() { foo(); }
> --
> 2.46.0
>
  

Patch

diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 50fc51152ca..eeabcb4af6f 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -6731,6 +6731,51 @@  simplify_context::simplify_relational_operation_1 (rtx_code code,
 	}
     }
 
+  /* Several optimizable scenerios of (op (and/ior x C1) C2) */
+  if ((op0code == AND || op0code == IOR)
+      && CONST_INT_P (op1)
+      && CONST_INT_P (XEXP (op0, 1)))
+    {
+      unsigned HOST_WIDE_INT c1 = UINTVAL (XEXP (op0, 1));
+      unsigned HOST_WIDE_INT c2 = UINTVAL (op1);
+
+      /* For AND operations:
+	   - (x & c1) == c2 when some bits are set in c2 but not in c1 -> false
+	   - (x & c1) != c2 when some bits are set in c2 but not in c1 -> true
+	   - (x & c1) >= c2 when c1 is less than c2 -> false
+	   - (x & c1) < c2 when c1 is less than c2 -> true
+	   - (x & c1) > c2 when c1 is less than or equal to c2 -> false
+	   - (x & c1) <= c2 when c1 is less than or equal to c2 -> true
+	 
+	 For IOR operations:
+	   - (x | c1) == c2 when some bits are set in c1 but not in c2 -> false
+	   - (x | c1) != c2 when some bits are set in c1 but not in c2 -> true
+	   - (x | c1) <= c2 when c1 is greater than c2 -> false
+	   - (x | c1) > c2 when c1 is greater than c2 -> true
+	   - (x | c1) < c2 when c1 is greater than or equal to c2 -> false
+	   - (x | c1) >= c2 when c1 is greater than or equal to c2 -> true */
+      if ((op0code == AND
+	   && ((code == EQ && (c1 & c2) != c2)
+	       || (code == GEU && c1 < c2)
+	       || (code == GTU && c1 <= c2)))
+	  || ((op0code == IOR
+	      && ((code == EQ && (c1 & c2) != c1)
+		  || (code == LEU && c1 > c2)
+		  || (code == LTU && c1 >= c2)))))
+	return const0_rtx;
+
+
+      if ((op0code == AND
+	   && ((code == NE && (c1 & c2) != c2)
+	       || (code == LTU && c1 < c2)
+	       || (code == LEU && c1 <= c2)))
+	  || ((op0code == IOR
+	      && ((code == NE && (c1 & c2) != c1)
+		  || (code == GTU && c1 > c2)
+		  || (code == GEU && c1 >= c2)))))
+	return const_true_rtx;
+    }
+
   /* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped.  */
   if ((code == EQ || code == NE)
       && GET_CODE (op0) == BSWAP
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c b/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
new file mode 100644
index 00000000000..3393bea8898
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
@@ -0,0 +1,32 @@ 
+/* { dg-do link  { target { rv64 } } } */
+/* { dg-options "-march=rv64gc_zbb_zbs -mabi=lp64d -flto" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */
+
+struct S {
+  int a;
+  char b;
+  int c;
+} s;
+
+const signed char c = -37;
+int d;
+struct S v1[] = {{0, 8}, 0, 0, -108976}, v2[] = {{}, 0, 0, 2804};
+int a;
+struct S v3[3];
+int *p = &a;
+
+void foo() {
+  int a;
+  if (a)
+    ;
+  else if (v1[0].b)
+    s.a = 0;
+  else
+    d = 0;
+  if (*p)
+    if (v3[1].c)
+      if (1 ^ (d & c & v2[1].c & ~v1[1].c | s.a))
+        v3[2].c = 0;
+}
+
+int main() { foo(); }