On Tue, Mar 31, 2026 at 3:12 AM Bohan Lei <[email protected]> wrote:
>
> This is v2 of
> https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711809.html, fixed
> and enhanced as was suggested by Philipp.
>
> 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/[email protected]/
>
> 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 | 30 +++++++++++++++++
> .../gcc.target/riscv/zbs-if_then_else-02.c | 32 +++++++++++++++++++
> 2 files changed, 62 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..abaee2423a7 100644
> --- a/gcc/simplify-rtx.cc
> +++ b/gcc/simplify-rtx.cc
> @@ -6731,6 +6731,36 @@ 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_SCALAR_INT_P (op1)
> + && CONST_SCALAR_INT_P (XEXP (op0, 1)))
> + {
> + unsigned HOST_WIDE_INT c1 = UINTVAL (XEXP (op0, 1));
> + unsigned HOST_WIDE_INT c2 = UINTVAL (op1);
If you are checking CONST_SCALAR_INT_P, you need to use
rtx_mode_t/wide_int instead.
Otherwise you change the check to CONST_INT_P and keep the UINTVAL.
As using CONST_WIDE_INT here can that will cause an ICE with RTL
checking and maybe even produce wrong code. E.g. using __int128.
> +
> + 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;
Can you add a comment before this mentioning each path down to 0 here?
Like say:
/*
(x & c1) == c2 when c1 and c2 don't share any bits -> false
*/
....
I have not checked but are these also implemented in match.pd? If not
please file a bug report for them.
Thanks,
Andrew
> +
> +
> + 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(); }
> --
> 2.46.0
>