https://gcc.gnu.org/g:b20e68022a3f49010028dc01dab570c68071e3db
commit r16-7123-gb20e68022a3f49010028dc01dab570c68071e3db Author: Uros Bizjak <[email protected]> Date: Wed Jan 28 21:57:47 2026 +0100 i386: Use x >> ~y for x >> 31-y [PR36503] x86 targets mask 32-bit shifts with a 5-bit mask (and 64-bit with 6-bit mask), so they can use x >> ~y instead of x >> 31-y. The optimization converts: movl $31, %ecx subl %esi, %ecx sall %cl, %eax to: notl %ecx sall %cl, %eax PR target/36503 gcc/ChangeLog: * config/i386/i386.md (*<insn:any_shift><mode:SWI48>3_sub): Also allow operands[3] & (<mode_bitsize>-1) == (<mode_bitsize>-1) in insn condition. Emit NOT RTX instead of NEG RTX in this case. (*<insn:any_shift><mode:SWI48>3_sub_1): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/pr36503-5.c: New test. * gcc.target/i386/pr36503-6.c: New test. Diff: --- gcc/config/i386/i386.md | 30 +++++++++++++++++++----------- gcc/testsuite/gcc.target/i386/pr36503-5.c | 20 ++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr36503-6.c | 19 +++++++++++++++++++ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 4444e5154af4..5c44988112b6 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -18266,24 +18266,27 @@ (match_operand 2 "int248_register_operand" "c,r")) 0))) (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands) - && (INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1)) == 0 + && ((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1)) == 0 + || (INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1)) + == <MODE_SIZE> * BITS_PER_UNIT - 1) && ix86_pre_reload_split ()" "#" "&& 1" [(parallel - [(set (match_dup 4) - (neg:QI (match_dup 2))) - (clobber (reg:CC FLAGS_REG))]) - (parallel [(set (match_dup 0) (any_shift:SWI48 (match_dup 1) (match_dup 4))) (clobber (reg:CC FLAGS_REG))])] { + HOST_WIDE_INT cnt = INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1); + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); operands[2] = gen_lowpart (QImode, operands[2]); operands[4] = gen_reg_rtx (QImode); + + rtx (*insn)(rtx, rtx) = (cnt == 0) ? gen_negqi2 : gen_one_cmplqi2; + emit_insn (insn (operands[4], operands[2])); } [(set_attr "isa" "*,bmi2")]) @@ -18296,20 +18299,25 @@ (match_operand:QI 2 "register_operand" "c,r")))) (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands) - && (INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1)) == 0 + && ((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1)) == 0 + || (INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1)) + == <MODE_SIZE> * BITS_PER_UNIT - 1) && ix86_pre_reload_split ()" "#" "&& 1" [(parallel - [(set (match_dup 4) - (neg:QI (match_dup 2))) - (clobber (reg:CC FLAGS_REG))]) - (parallel [(set (match_dup 0) (any_shift:SWI48 (match_dup 1) (match_dup 4))) (clobber (reg:CC FLAGS_REG))])] - "operands[4] = gen_reg_rtx (QImode);" +{ + HOST_WIDE_INT cnt = INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT - 1); + + operands[4] = gen_reg_rtx (QImode); + + rtx (*insn)(rtx, rtx) = (cnt == 0) ? gen_negqi2 : gen_one_cmplqi2; + emit_insn (insn (operands[4], operands[2])); +} [(set_attr "isa" "*,bmi2")]) (define_insn_and_split "*extend<dwi>2_doubleword_highpart" diff --git a/gcc/testsuite/gcc.target/i386/pr36503-5.c b/gcc/testsuite/gcc.target/i386/pr36503-5.c new file mode 100644 index 000000000000..345225585240 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr36503-5.c @@ -0,0 +1,20 @@ +/* PR target/36503 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -masm=att" } */ +/* { dg-additional-options "-mregparm=3" { target ia32 } } */ +/* { dg-final { scan-assembler-not "movl\[ \\t\]+\\\$31" } } */ + +int foo (int i, int n) +{ + return i << (31 - n); +} + +int bar (int i, int n) +{ + return i >> (31 - n); +} + +unsigned int baz (unsigned int i, int n) +{ + return i >> (31 - n); +} diff --git a/gcc/testsuite/gcc.target/i386/pr36503-6.c b/gcc/testsuite/gcc.target/i386/pr36503-6.c new file mode 100644 index 000000000000..cf16407dfcbf --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr36503-6.c @@ -0,0 +1,19 @@ +/* PR target/36503 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -masm=att" } */ +/* { dg-final { scan-assembler-not "movl\[ \\t\]+\\\$63" } } */ + +long long foo (long long i, int n) +{ + return i << (63 - n); +} + +long long bar (long long i, int n) +{ + return i >> (63 - n); +} + +unsigned long long baz (unsigned long long i, int n) +{ + return i >> (63 - n); +}
