From: Bohan Lei Date: Tue, 31 Mar 2026 07:27:05 +0000 (+0800) Subject: simplify-rtx: Simplify (cmp (and/ior x C1) C2) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6becc7cc2c06b3941d829e08100a6ff70cc55262;p=thirdparty%2Fgcc.git simplify-rtx: Simplify (cmp (and/ior x C1) C2) This is v6 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-April/714878.html. Andrew noticed the x86 regression and suggested updating the testcase. This patch adds missing simplifications for (cmp (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 `(cmp (and/ior x C1) C2)`. gcc/testsuite/ChangeLog: * gcc.target/i386/pr113609-1.c: Change assembly check after optimization. * gcc.target/riscv/zbs-if_then_else-02.c: New test. --- diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index 73363a77a4e..a87d91884df 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -6747,6 +6747,51 @@ simplify_context::simplify_relational_operation_1 (rtx_code code, } } + /* 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; + + 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/i386/pr113609-1.c b/gcc/testsuite/gcc.target/i386/pr113609-1.c index f0639b8500a..be20bbb86ee 100644 --- a/gcc/testsuite/gcc.target/i386/pr113609-1.c +++ b/gcc/testsuite/gcc.target/i386/pr113609-1.c @@ -9,9 +9,9 @@ /* { dg-final { scan-assembler-times "\[ \\t\]+sete" 1 { target { ia32 } } } } */ /* { dg-final { scan-assembler-times "\[ \\t\]+setne" 1 { target { ia32 } } } } */ /* { dg-final { scan-assembler-times "\[ \\t\]+je" 1 { target { ia32 } } } } */ -/* { dg-final { scan-assembler-times "\[ \\t\]+jne" 2 { target { ia32 } } } } */ +/* { dg-final { scan-assembler-times "\[ \\t\]+jne" 1 { target { ia32 } } } } */ /* { dg-final { scan-assembler-times "kortest" 12 { target { ia32 } } } } */ -/* { dg-final { scan-assembler-times "kortest" 17 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "kortest" 16 { target { ! ia32 } } } } */ #include 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(); }