re PR target/84431 (Suboptimal code for masked shifts (x86/x86-64))
authorUros Bizjak <ubizjak@gmail.com>
Sat, 28 Apr 2018 07:37:04 +0000 (09:37 +0200)
committerUros Bizjak <uros@gcc.gnu.org>
Sat, 28 Apr 2018 07:37:04 +0000 (09:37 +0200)
PR target/84431
* config/i386/i386.md (*ashl<dwi>3_doubleword_mask): New pattern.
(*ashl<dwi>3_doubleword_mask_1): Ditto.
(*<shift_insn><dwi>3_doubleword_mask): Ditto.
(*<shift_insn><dwi>3_doubleword_mask_1): Ditto.

testsuite/ChangeLog:

PR target/84431
* gcc.target/i386/pr84431.c: New test.

From-SVN: r259739

gcc/ChangeLog
gcc/config/i386/i386.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr84431.c [new file with mode: 0644]

index edc952c..1433190 100644 (file)
@@ -1,3 +1,11 @@
+2018-04-28  Uros Bizjak  <ubizjak@gmail.com>
+
+       PR target/84431
+       * config/i386/i386.md (*ashl<dwi>3_doubleword_mask): New pattern.
+       (*ashl<dwi>3_doubleword_mask_1): Ditto.
+       (*<shift_insn><dwi>3_doubleword_mask): Ditto.
+       (*<shift_insn><dwi>3_doubleword_mask_1): Ditto.
+
 2018-04-28  Richard Biener  <rguenther@suse.de>
 
        * tree-cfg.c (verify_gimple_phi): Take a gphi * argument.
index eacc3bb..d85d346 100644 (file)
   ""
   "ix86_expand_binary_operator (ASHIFT, <MODE>mode, operands); DONE;")
 
+(define_insn_and_split "*ashl<dwi>3_doubleword_mask"
+  [(set (match_operand:<DWI> 0 "register_operand")
+       (ashift:<DWI>
+         (match_operand:<DWI> 1 "register_operand")
+         (subreg:QI
+           (and:SI
+             (match_operand:SI 2 "register_operand" "c")
+             (match_operand:SI 3 "const_int_operand")) 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(parallel
+     [(set (match_dup 6)
+          (ior:DWIH (ashift:DWIH (match_dup 6) (match_dup 2))
+                    (lshiftrt:DWIH (match_dup 5)
+                      (minus:QI (match_dup 8) (match_dup 2)))))
+      (clobber (reg:CC FLAGS_REG))])
+   (parallel
+     [(set (match_dup 4)
+          (ashift:DWIH (match_dup 5) (match_dup 2)))
+      (clobber (reg:CC FLAGS_REG))])]
+{
+  split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]);
+
+  operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT);
+
+  if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1)
+    emit_insn (gen_andsi3 (operands[2], operands[2], operands[3]));
+
+  operands[2] = gen_lowpart (QImode, operands[2]);
+
+  if (!rtx_equal_p (operands[6], operands[7]))
+    emit_move_insn (operands[6], operands[7]);
+})
+
+(define_insn_and_split "*ashl<dwi>3_doubleword_mask_1"
+  [(set (match_operand:<DWI> 0 "register_operand")
+       (ashift:<DWI>
+         (match_operand:<DWI> 1 "register_operand")
+         (and:QI
+           (match_operand:QI 2 "register_operand" "c")
+           (match_operand:QI 3 "const_int_operand"))))
+   (clobber (reg:CC FLAGS_REG))]
+  "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(parallel
+     [(set (match_dup 6)
+          (ior:DWIH (ashift:DWIH (match_dup 6) (match_dup 2))
+                    (lshiftrt:DWIH (match_dup 5)
+                      (minus:QI (match_dup 8) (match_dup 2)))))
+      (clobber (reg:CC FLAGS_REG))])
+   (parallel
+     [(set (match_dup 4)
+          (ashift:DWIH (match_dup 5) (match_dup 2)))
+      (clobber (reg:CC FLAGS_REG))])]
+{
+  split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]);
+
+  operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT);
+
+  if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1)
+    emit_insn (gen_andqi3 (operands[2], operands[2], operands[3]));
+
+  if (!rtx_equal_p (operands[6], operands[7]))
+    emit_move_insn (operands[6], operands[7]);
+})
+
 (define_insn "*ashl<mode>3_doubleword"
   [(set (match_operand:DWI 0 "register_operand" "=&r")
        (ashift:DWI (match_operand:DWI 1 "reg_or_pm1_operand" "0n")
   ""
   [(set_attr "isa" "*,bmi2")])
 
+(define_insn_and_split "*<shift_insn><dwi>3_doubleword_mask"
+  [(set (match_operand:<DWI> 0 "register_operand")
+       (any_shiftrt:<DWI>
+         (match_operand:<DWI> 1 "register_operand")
+         (subreg:QI
+           (and:SI
+             (match_operand:SI 2 "register_operand" "c")
+             (match_operand:SI 3 "const_int_operand")) 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(parallel
+     [(set (match_dup 4)
+          (ior:DWIH (lshiftrt:DWIH (match_dup 4) (match_dup 2))
+                    (ashift:DWIH (match_dup 7)
+                      (minus:QI (match_dup 8) (match_dup 2)))))
+      (clobber (reg:CC FLAGS_REG))])
+   (parallel
+     [(set (match_dup 6)
+          (any_shiftrt:DWIH (match_dup 7) (match_dup 2)))
+      (clobber (reg:CC FLAGS_REG))])]
+{
+  split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]);
+
+  operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT);
+
+  if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1)
+    emit_insn (gen_andsi3 (operands[2], operands[2], operands[3]));
+
+  operands[2] = gen_lowpart (QImode, operands[2]);
+
+  if (!rtx_equal_p (operands[4], operands[5]))
+    emit_move_insn (operands[4], operands[5]);
+})
+
+(define_insn_and_split "*<shift_insn><dwi>3_doubleword_mask_1"
+  [(set (match_operand:<DWI> 0 "register_operand")
+       (any_shiftrt:<DWI>
+         (match_operand:<DWI> 1 "register_operand")
+         (and:QI
+           (match_operand:QI 2 "register_operand" "c")
+           (match_operand:QI 3 "const_int_operand"))))
+   (clobber (reg:CC FLAGS_REG))]
+  "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(parallel
+     [(set (match_dup 4)
+          (ior:DWIH (lshiftrt:DWIH (match_dup 4) (match_dup 2))
+                    (ashift:DWIH (match_dup 7)
+                      (minus:QI (match_dup 8) (match_dup 2)))))
+      (clobber (reg:CC FLAGS_REG))])
+   (parallel
+     [(set (match_dup 6)
+          (any_shiftrt:DWIH (match_dup 7) (match_dup 2)))
+      (clobber (reg:CC FLAGS_REG))])]
+{
+  split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]);
+
+  operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT);
+
+  if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1)
+    emit_insn (gen_andqi3 (operands[2], operands[2], operands[3]));
+
+  if (!rtx_equal_p (operands[4], operands[5]))
+    emit_move_insn (operands[4], operands[5]);
+})
+
 (define_insn_and_split "*<shift_insn><mode>3_doubleword"
   [(set (match_operand:DWI 0 "register_operand" "=&r")
        (any_shiftrt:DWI (match_operand:DWI 1 "register_operand" "0")
index 47da043..ccc4d18 100644 (file)
@@ -1,3 +1,8 @@
+2018-04-28  Uros Bizjak  <ubizjak@gmail.com>
+
+       PR target/84431
+       * gcc.target/i386/pr84431.c: New test.
+
 2018-04-27  Martin Jambor  <mjambor@suse.cz>
 
        PR ipa/85549
diff --git a/gcc/testsuite/gcc.target/i386/pr84431.c b/gcc/testsuite/gcc.target/i386/pr84431.c
new file mode 100644 (file)
index 0000000..ee751a7
--- /dev/null
@@ -0,0 +1,19 @@
+/* PR target/84431 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#ifdef __SIZEOF_INT128__
+typedef unsigned __int128 U;
+typedef signed __int128 S;
+# define M 63
+#else
+typedef unsigned long long U;
+typedef signed long long S;
+# define M 31
+#endif
+
+S f1 (S a, int s) { return a >> (s & M); }
+U f2 (U a, int s) { return a >> (s & M); }
+U f3 (U a, int s) { return a << (s & M); }
+
+/* { dg-final { scan-assembler-not "and" } } */