https://gcc.gnu.org/g:c05164c348242b00b33cdf2988cc5e93d29b0478

commit r17-1680-gc05164c348242b00b33cdf2988cc5e93d29b0478
Author: Milan Tripkovic <[email protected]>
Date:   Thu Jun 18 17:51:59 2026 -0600

    [PATCH] PR tree-optimization/125405: Missed optimization: mask/sub 
sign-extension idiom not canonicalized to sign extension
    
    This patch implement new pattern for match.pd that recognize the
    sign-extension idiom (x & low_bits) - (x & sign_bit) and tests that covers 
it.
    Pattern is based on conversation from bug report.
    
    TRUNK riscv output:
     sext8_hd:
              andi    a5,a0,127
              andi    a0,a0,128
              sub     a0,a5,a0
              ret
    
     sext16_hd:
              slli    a5,a0,49
              li      a4,32768
              srli    a5,a5,49
              and     a0,a0,a4
              sub     a0,a5,a0
              ret
    
    NEW riscv output:
    sext8_hd:
            slliw   a0,a0,24
            sraiw   a0,a0,24
            ret
    
    sext16_hd:
            slliw   a0,a0,16
            sraiw   a0,a0,16
            ret
    
    TRUNK x86 output:
    "sext8_hd":
            mov     rax, rdi
            and     edi, 128
            and     eax, 127
            sub     rax, rdi
            ret
    
    "sext16_hd":
            mov     rax, rdi
            and     edi, 32768
            and     eax, 32767
            sub     rax, rdi
            ret
    
    new x86 output:
    sext8_hd:
            movsbq  %dil, %rax
            ret
    
    sext16_hd:
            movswq  %di, %rax
            ret
    
            PR target/125405
    
    gcc/ChangeLog:
    
            * match.pd: New pattern added.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/pr125405-bitint.c: New test.
            * gcc.dg/tree-ssa/pr125405.c: New test.
            * gcc.target/riscv/pr125405.c: New test.

Diff:
---
 gcc/match.pd                              | 17 +++++++++++++++
 gcc/testsuite/gcc.dg/pr125405-bitint.c    | 36 +++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr125405.c  | 24 +++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr125405.c | 22 +++++++++++++++++++
 4 files changed, 99 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index 475939a0b638..fdc2cf88e906 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4958,6 +4958,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (if (stype && (width == 1 || type_has_mode_precision_p (stype)))
       (convert (convert:stype @0))))))))
 
+/* PR125405: (x & ((1 << (N - 1)) - 1)) - (x & (1 << (N - 1)))
+   -> sign_extend<N> (x). */
+(simplify
+ (minus (bit_and @0 INTEGER_CST@1) (bit_and @0 integer_pow2p@2))
+ (if (INTEGRAL_TYPE_P (type)
+      && TYPE_PRECISION (type) <= MAX_FIXED_MODE_SIZE
+      && wi::to_wide (@1) + 1 == wi::to_wide (@2))
+  (with {
+    int width = wi::exact_log2 (wi::to_wide (@2)) + 1;
+    tree ntype = NULL_TREE;
+
+    if (width > 0 && width < TYPE_PRECISION (type))
+      ntype = build_nonstandard_integer_type (width, SIGNED);
+   }
+   (if (ntype && type_has_mode_precision_p (ntype))
+    (convert (convert:ntype @0))))))
+
 /* Optimize x >> x into 0 */
 (simplify
  (rshift @0 @0)
diff --git a/gcc/testsuite/gcc.dg/pr125405-bitint.c 
b/gcc/testsuite/gcc.dg/pr125405-bitint.c
new file mode 100644
index 000000000000..857dc0f7b3e0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr125405-bitint.c
@@ -0,0 +1,36 @@
+/* PR tree-optimization/125405 */
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned _BitInt(32)
+sext8_bitint32 (unsigned _BitInt(32) x)
+{
+  return (x & (unsigned _BitInt(32)) 0x7f)
+         - (x & (unsigned _BitInt(32)) 0x80);
+}
+
+unsigned _BitInt(32)
+sext16_bitint32 (unsigned _BitInt(32) x)
+{
+  return (x & (unsigned _BitInt(32)) 0x7fff)
+         - (x & (unsigned _BitInt(32)) 0x8000);
+}
+
+unsigned _BitInt(32)
+no_sext_bad_masks (unsigned _BitInt(32) x)
+{
+  return (x & (unsigned _BitInt(32)) 0x7e)
+         - (x & (unsigned _BitInt(32)) 0x80);
+}
+
+unsigned _BitInt(32)
+no_sext_bad_pair (unsigned _BitInt(32) x)
+{
+  return (x & (unsigned _BitInt(32)) 0xff)
+         - (x & (unsigned _BitInt(32)) 0x80);
+}
+
+/* { dg-final { scan-tree-dump-times "\\(signed char\\)" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\\(signed short\\)" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " & 126" "optimized" } } */
+/* { dg-final { scan-tree-dump " & 255" "optimized" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr125405.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr125405.c
new file mode 100644
index 000000000000..175c6b7af631
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr125405.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/125405 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+typedef unsigned long xlen_t;
+
+xlen_t
+sext8_hd (xlen_t x)
+{
+  return (x & 0x7fUL) - (x & 0x80UL);
+}
+
+xlen_t
+sext16_hd (xlen_t x)
+{
+  return (x & 0x7fffUL) - (x & 0x8000UL);
+}
+
+/* { dg-final { scan-tree-dump-times "\\(signed char\\)" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\\(signed short\\)" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-not " & 127" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " & 128" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " & 32767" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " & 32768" "optimized" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/pr125405.c 
b/gcc/testsuite/gcc.target/riscv/pr125405.c
new file mode 100644
index 000000000000..2aacad89b6c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr125405.c
@@ -0,0 +1,22 @@
+/* PR tree-optimization/125405 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gc -mabi=lp64d" } */
+
+typedef unsigned long xlen_t;
+
+xlen_t
+sext8_hd (xlen_t x)
+{
+  return (x & 0x7fUL) - (x & 0x80UL);
+}
+
+xlen_t
+sext16_hd (xlen_t x)
+{
+  return (x & 0x7fffUL) - (x & 0x8000UL);
+}
+
+/* { dg-final { scan-assembler-times "\\mslliw\\M" 2 } } */
+/* { dg-final { scan-assembler-times "\\msraiw\\M" 2 } } */
+/* { dg-final { scan-assembler-not "\\mandi\\M" } } */
+/* { dg-final { scan-assembler-not "\\msub\\M" } } */
\ No newline at end of file

Reply via email to