On Fri, Dec 4, 2020 at 6:32 PM Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > As mentioned in the PR, we can combine ~(1 << x) into -2 r<< x, but we give > up in the ~(1 << (x & 31)) cases, as *<rotate_insn><mode>3_mask* don't allow > immediate operand 1 and find_split_point prefers to split (x & 31) instead > of the constant. > > With these combine splitters we help combine decide how to split those > insns. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2020-12-04 Jakub Jelinek <ja...@redhat.com> > > PR target/96226 > * config/i386/i386.md (splitter after *<rotate_insn><mode>3_mask, > splitter after *<rotate_insn><mode>3_mask_1): New combine splitters. > > * gcc.target/i386/pr96226.c: New test. > > --- gcc/config/i386/i386.md.jj 2020-12-02 11:20:24.729487245 +0100 > +++ gcc/config/i386/i386.md 2020-12-04 15:39:17.481148449 +0100 > @@ -11975,6 +11975,23 @@ (define_insn_and_split "*<rotate_insn><m > (clobber (reg:CC FLAGS_REG))])] > "operands[2] = gen_lowpart (QImode, operands[2]);") > > +(define_split > + [(set (match_operand:SWI48 0 "register_operand") > + (any_rotate:SWI48 > + (match_operand:SWI48 1 "const_int_operand") > + (subreg:QI > + (and:SI > + (match_operand:SI 2 "register_operand") > + (match_operand:SI 3 "const_int_operand")) 0)))] > + "(INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) > + == GET_MODE_BITSIZE (<MODE>mode) - 1" > + [(set (match_dup 4) (match_dup 1)) > + (set (match_dup 0) > + (any_rotate:SWI48 (match_dup 4) > + (subreg:QI > + (and:SI (match_dup 2) (match_dup 3)) 0)))]
Don't we need (clobber (reg:CC FLAGS_REG))] here? (or is this one of the combine splitter peculiarities?) Uros. > + "operands[4] = gen_reg_rtx (<MODE>mode);") > + > (define_insn_and_split "*<rotate_insn><mode>3_mask_1" > [(set (match_operand:SWI48 0 "nonimmediate_operand") > (any_rotate:SWI48 > @@ -11995,6 +12012,21 @@ (define_insn_and_split "*<rotate_insn><m > (match_dup 2))) > (clobber (reg:CC FLAGS_REG))])]) > > +(define_split > + [(set (match_operand:SWI48 0 "register_operand") > + (any_rotate:SWI48 > + (match_operand:SWI48 1 "const_int_operand") > + (and:QI > + (match_operand:QI 2 "register_operand") > + (match_operand:QI 3 "const_int_operand"))))] > + "(INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) > + == GET_MODE_BITSIZE (<MODE>mode) - 1" > + [(set (match_dup 4) (match_dup 1)) > + (set (match_dup 0) > + (any_rotate:SWI48 (match_dup 4) > + (and:QI (match_dup 2) (match_dup 3))))] > + "operands[4] = gen_reg_rtx (<MODE>mode);") > + > ;; Implement rotation using two double-precision > ;; shift instructions and a scratch register. > > --- gcc/testsuite/gcc.target/i386/pr96226.c.jj 2020-12-04 15:45:35.437890237 > +0100 > +++ gcc/testsuite/gcc.target/i386/pr96226.c 2020-12-04 15:46:09.408507488 > +0100 > @@ -0,0 +1,16 @@ > +/* PR target/96226 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > +/* { dg-final { scan-assembler-times "\troll\t" 4 } } */ > +/* { dg-final { scan-assembler-times "\trolq\t" 4 { target { ! ia32 } } } } > */ > + > +int f1 (int x) { return ~(1U << (x & 0x1f)); } > +int f2 (int x) { return ~(1U << x); } > +int f3 (unsigned char *x) { return ~(1U << (x[0] & 0x1f)); } > +int f4 (unsigned char *x) { return ~(1U << x[0]); } > +#ifdef __x86_64__ > +long int f5 (int x) { return ~(1ULL << (x & 0x3f)); } > +long int f6 (int x) { return ~(1ULL << x); } > +long int f7 (unsigned char *x) { return ~(1ULL << (x[0] & 0x3f)); } > +long int f8 (unsigned char *x) { return ~(1ULL << x[0]); } > +#endif > > Jakub >