From: Uros Bizjak Date: Sun, 24 Nov 2024 21:00:18 +0000 (+0100) Subject: i386: x86 can use x >> -y for x >> 32-y [PR36503] X-Git-Tag: basepoints/gcc-16~3918 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1ff69000b50e8ac184e925af71e794e7c3d5d2a6;p=thirdparty%2Fgcc.git i386: x86 can use x >> -y for x >> 32-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 >> 32-y. This form is very common in bitstream readers, where it's used to read the top N bits from a word. The optimization converts: movl $32, %ecx subl %esi, %ecx sall %cl, %eax to: negl %ecx sall %cl, %eax PR target/36503 gcc/ChangeLog: * config/i386/i386.md (*ashl3_negcnt): New define_insn_and_split pattern. (*ashl3_negcnt_1): Ditto. (*3_negcnt): Ditto. (*3_negcnt_1): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/pr36503-1.c: New test. * gcc.target/i386/pr36503-2.c: New test. --- diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 1c1bf659fc25..399a6a81f9ca 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -15896,6 +15896,62 @@ "" [(set_attr "isa" "*,bmi2")]) +(define_insn_and_split "*ashl3_negcnt" + [(set (match_operand:SWI48 0 "nonimmediate_operand") + (ashift:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand") + (subreg:QI + (minus + (match_operand 3 "const_int_operand") + (match_operand 2 "int248_register_operand" "c,r")) 0))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (ASHIFT, mode, operands) + && INTVAL (operands[3]) == * BITS_PER_UNIT + && 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) + (ashift:SWI48 (match_dup 1) + (match_dup 4))) + (clobber (reg:CC FLAGS_REG))])] +{ + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); + + operands[4] = gen_reg_rtx (QImode); +} + [(set_attr "isa" "*,bmi2")]) + +(define_insn_and_split "*ashl3_negcnt_1" + [(set (match_operand:SWI48 0 "nonimmediate_operand") + (ashift:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand") + (minus:QI + (match_operand:QI 3 "const_int_operand") + (match_operand:QI 2 "register_operand" "c,r")))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (ASHIFT, mode, operands) + && INTVAL (operands[3]) == * BITS_PER_UNIT + && 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) + (ashift:SWI48 (match_dup 1) + (match_dup 4))) + (clobber (reg:CC FLAGS_REG))])] + "operands[4] = gen_reg_rtx (QImode);" + [(set_attr "isa" "*,bmi2")]) + (define_insn "*bmi2_ashl3_1" [(set (match_operand:SWI48 0 "register_operand" "=r") (ashift:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm") @@ -16622,6 +16678,62 @@ "" [(set_attr "isa" "*,bmi2")]) +(define_insn_and_split "*3_negcnt" + [(set (match_operand:SWI48 0 "nonimmediate_operand") + (any_shiftrt:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand") + (subreg:QI + (minus + (match_operand 3 "const_int_operand") + (match_operand 2 "int248_register_operand" "c,r")) 0))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (, mode, operands) + && INTVAL (operands[3]) == * BITS_PER_UNIT + && 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_shiftrt:SWI48 (match_dup 1) + (match_dup 4))) + (clobber (reg:CC FLAGS_REG))])] +{ + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); + + operands[4] = gen_reg_rtx (QImode); +} + [(set_attr "isa" "*,bmi2")]) + +(define_insn_and_split "*3_negcnt_1" + [(set (match_operand:SWI48 0 "nonimmediate_operand") + (any_shiftrt:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand") + (minus:QI + (match_operand:QI 3 "const_int_operand") + (match_operand:QI 2 "register_operand" "c,r")))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (, mode, operands) + && INTVAL (operands[3]) == * BITS_PER_UNIT + && 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_shiftrt:SWI48 (match_dup 1) + (match_dup 4))) + (clobber (reg:CC FLAGS_REG))])] + "operands[4] = gen_reg_rtx (QImode);" + [(set_attr "isa" "*,bmi2")]) + (define_insn_and_split "*3_doubleword_mask" [(set (match_operand: 0 "register_operand") (any_shiftrt: diff --git a/gcc/testsuite/gcc.target/i386/pr36503-1.c b/gcc/testsuite/gcc.target/i386/pr36503-1.c new file mode 100644 index 000000000000..d94fabb827e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr36503-1.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\]+\\\$32" } } */ + +int foo (int i, int n) +{ + return i << (32 - n); +} + +int bar (int i, int n) +{ + return i >> (32 - n); +} + +unsigned int baz (unsigned int i, int n) +{ + return i >> (32 - n); +} diff --git a/gcc/testsuite/gcc.target/i386/pr36503-2.c b/gcc/testsuite/gcc.target/i386/pr36503-2.c new file mode 100644 index 000000000000..e1f7a1cf44fc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr36503-2.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\]+\\\$64" } } */ + +long long foo (long long i, int n) +{ + return i << (64 - n); +} + +long long bar (long long i, int n) +{ + return i >> (64 - n); +} + +unsigned long long baz (unsigned long long i, int n) +{ + return i >> (64 - n); +}