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
2026-06-15 Milan Tripkovic <[email protected]>
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.
CONFIDENTIALITY: The contents of this e-mail are confidential and intended only
for the above addressee(s). If you are not the intended recipient, or the
person responsible for delivering it to the intended recipient, copying or
delivering it to anyone else or using it in any unauthorized manner is
prohibited and may be unlawful. If you receive this e-mail by mistake, please
notify the sender and the systems administrator at [email protected]
immediately.
---
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(+)
create mode 100644 gcc/testsuite/gcc.dg/pr125405-bitint.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr125405.c
create mode 100644 gcc/testsuite/gcc.target/riscv/pr125405.c
diff --git a/gcc/match.pd b/gcc/match.pd
index e0d7ef80e1..32d803f362 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4927,6 +4927,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 0000000000..857dc0f7b3
--- /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 0000000000..175c6b7af6
--- /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 0000000000..2aacad89b6
--- /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
--
2.34.1