i386: Add combine splitters to allow combining multiple insns into reg1 = const;...
authorJakub Jelinek <jakub@redhat.com>
Fri, 4 Dec 2020 17:44:31 +0000 (18:44 +0100)
committerJakub Jelinek <jakub@redhat.com>
Fri, 4 Dec 2020 17:44:31 +0000 (18:44 +0100)
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.

2020-12-04  Jakub Jelinek  <jakub@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
gcc/testsuite/gcc.target/i386/pr96226.c [new file with mode: 0644]

index 76e9499ad74f2991d01b98ede5492caf8cdf274f..129d47bb0263096fd1a08e75ab46fa91e00170ec 100644 (file)
       (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)))]
+ "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
                             (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.
 
diff --git a/gcc/testsuite/gcc.target/i386/pr96226.c b/gcc/testsuite/gcc.target/i386/pr96226.c
new file mode 100644 (file)
index 0000000..cc010fa
--- /dev/null
@@ -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