diff mbox series

[i386] : Fix PR84431, suboptimal code for masked shifts

Message ID CAFULd4bqwOWGWp8Q6gXr5EQ7W=KS1eaiL0FFAew1NgRYoB+YxQ@mail.gmail.com
State New
Headers show
Series [i386] : Fix PR84431, suboptimal code for masked shifts | expand

Commit Message

Uros Bizjak April 28, 2018, 7:38 a.m. UTC
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.

testsuite/ChangeLog:

2018-04-28  Uros Bizjak  <ubizjak@gmail.com>

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

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Committed to mainline SVN.

Uros.
diff mbox series

Patch

Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md	(revision 259701)
+++ config/i386/i386.md	(working copy)
@@ -10357,6 +10357,77 @@ 
   ""
   "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")
@@ -11038,6 +11109,77 @@ 
   ""
   [(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: testsuite/gcc.target/i386/pr84431.c
===================================================================
--- testsuite/gcc.target/i386/pr84431.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr84431.c	(working copy)
@@ -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" } } */