From ac2a6962b91128e700ee52db686dcdb2bab93790 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 4 Dec 2020 18:44:31 +0100 Subject: [PATCH] i386: Add combine splitters to allow combining multiple insns into reg1 = const; reg2 = rotate (reg1, reg3 & cst) [PR96226] 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 *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. 2020-12-04 Jakub Jelinek PR target/96226 * config/i386/i386.md (splitter after *3_mask, splitter after *3_mask_1): New combine splitters. * gcc.target/i386/pr96226.c: New test. --- gcc/config/i386/i386.md | 32 +++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr96226.c | 16 +++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr96226.c diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 76e9499ad74..129d47bb026 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -11975,6 +11975,23 @@ (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) - 1)) + == GET_MODE_BITSIZE (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)))] + "operands[4] = gen_reg_rtx (mode);") + (define_insn_and_split "*3_mask_1" [(set (match_operand:SWI48 0 "nonimmediate_operand") (any_rotate:SWI48 @@ -11995,6 +12012,21 @@ (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) - 1)) + == GET_MODE_BITSIZE (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);") + ;; Implement rotation using two double-precision ;; shift instructions and a scratch register. diff --git a/gcc/testsuite/gcc.target/i386/pr96226.c b/gcc/testsuite/gcc.target/i386/pr96226.c new file mode 100644 index 00000000000..cc010faa135 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr96226.c @@ -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 -- 2.30.2