re PR middle-end/17886 (variable rotate and unsigned long long rotate should be bette...
authorMark Mitchell <mark@codesourcery.com>
Thu, 29 Sep 2005 03:31:23 +0000 (03:31 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Thu, 29 Sep 2005 03:31:23 +0000 (03:31 +0000)
PR 17886
* expmed.c (expand_shift): Move logic to reverse rotation
direction when  rotating by constants ...
* optabs.c (expand_binop): ... here.
* config/i386/i386.md (rotrdi3): Handle 32-bit mode.
(ix86_rotrdi3): New pattern.
(rotldi3): Handle 32-bit mode.
(ix86_rotldi3): New pattern.

From-SVN: r104761

gcc/ChangeLog
gcc/config/i386/i386.md
gcc/expmed.c
gcc/optabs.c

index f427dbf225d1dd020d95c7c642a777447c177b8d..fdbecf6c7091f9e83786459c370ca0947f5dde55 100644 (file)
@@ -1,3 +1,14 @@
+2005-09-28  Mark Mitchell  <mark@codesourcery.com>
+
+       PR 17886
+       * expmed.c (expand_shift): Move logic to reverse rotation
+       direction when  rotating by constants ...
+       * optabs.c (expand_binop): ... here.
+       * config/i386/i386.md (rotrdi3): Handle 32-bit mode.
+       (ix86_rotrdi3): New pattern.
+       (rotldi3): Handle 32-bit mode.
+       (ix86_rotldi3): New pattern.
+
 2005-09-29  Alan Modra  <amodra@bigpond.net.au>
 
        PR target/24102
index 8bfa037a8cc07e21c165c9718a3f263bc989e3a6..6b1beaf020412a15f73a0c8ea39179dce5160b91 100644 (file)
 ;; Rotate instructions
 
 (define_expand "rotldi3"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "")
+  [(set (match_operand:DI 0 "shiftdi_operand" "")
+       (rotate:DI (match_operand:DI 1 "shiftdi_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_64BIT"
-  "ix86_expand_binary_operator (ROTATE, DImode, operands); DONE;")
+ ""
+{
+  if (TARGET_64BIT)
+    {
+      ix86_expand_binary_operator (ROTATE, DImode, operands);
+      DONE;
+    }
+  if (!const_1_to_31_operand (operands[2], VOIDmode))
+    FAIL;
+  emit_insn (gen_ix86_rotldi3 (operands[0], operands[1], operands[2]));
+  DONE;
+})
 
+;; Implement rotation using two double-precision shift instructions
+;; and a scratch register.   
+(define_insn_and_split "ix86_rotldi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+       (rotate:DI (match_operand:DI 1 "register_operand" "0")
+                  (match_operand:QI 2 "const_1_to_31_operand" "I")))
+  (clobber (reg:CC FLAGS_REG))
+  (clobber (match_scratch:SI 3 "=&r"))]
+ "!TARGET_64BIT"
+ "" 
+ "&& reload_completed"
+ [(set (match_dup 3) (match_dup 4))
+  (parallel
+   [(set (match_dup 4)
+         (ior:SI (ashift:SI (match_dup 4) (match_dup 2))
+                 (lshiftrt:SI (match_dup 5)
+                              (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])
+  (parallel
+   [(set (match_dup 5)
+         (ior:SI (ashift:SI (match_dup 5) (match_dup 2))
+                 (lshiftrt:SI (match_dup 3)
+                              (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])]
+ "split_di (operands, 1, operands + 4, operands + 5);")
 (define_insn "*rotlsi3_1_one_bit_rex64"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0")
    (set_attr "mode" "QI")])
 
 (define_expand "rotrdi3"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "")
-                    (match_operand:QI 2 "nonmemory_operand" "")))
+  [(set (match_operand:DI 0 "shiftdi_operand" "")
+       (rotate:DI (match_operand:DI 1 "shiftdi_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_64BIT"
-  "ix86_expand_binary_operator (ROTATERT, DImode, operands); DONE;")
+ ""
+{
+  if (TARGET_64BIT)
+    {
+      ix86_expand_binary_operator (ROTATERT, DImode, operands);
+      DONE;
+    }
+  if (!const_1_to_31_operand (operands[2], VOIDmode))
+    FAIL;
+  emit_insn (gen_ix86_rotrdi3 (operands[0], operands[1], operands[2]));
+  DONE;
+})
+  
+;; Implement rotation using two double-precision shift instructions
+;; and a scratch register.   
+(define_insn_and_split "ix86_rotrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+       (rotatert:DI (match_operand:DI 1 "register_operand" "0")
+                    (match_operand:QI 2 "const_1_to_31_operand" "I")))
+  (clobber (reg:CC FLAGS_REG))
+  (clobber (match_scratch:SI 3 "=&r"))]
+ "!TARGET_64BIT"
+ ""
+ "&& reload_completed"
+ [(set (match_dup 3) (match_dup 4))
+  (parallel
+   [(set (match_dup 4)
+         (ior:SI (ashiftrt:SI (match_dup 4) (match_dup 2))
+                 (ashift:SI (match_dup 5)
+                            (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])
+  (parallel
+   [(set (match_dup 5)
+         (ior:SI (ashiftrt:SI (match_dup 5) (match_dup 2))
+                 (ashift:SI (match_dup 3)
+                            (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])]
+ "split_di (operands, 1, operands + 4, operands + 5);")
 
 (define_insn "*rotrdi3_1_one_bit_rex64"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
index 5da9084651f2dae1d39da4cdf4eb2d9b82ad826a..19d972d2ad38c8367c8503486b5d471d014c907d 100644 (file)
@@ -2237,19 +2237,6 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
          temp = expand_binop (mode,
                               left ? rotl_optab : rotr_optab,
                               shifted, op1, target, unsignedp, methods);
-
-         /* If we don't have the rotate, but we are rotating by a constant
-            that is in range, try a rotate in the opposite direction.  */
-
-         if (temp == 0 && GET_CODE (op1) == CONST_INT
-             && INTVAL (op1) > 0
-             && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
-           temp = expand_binop (mode,
-                                left ? rotr_optab : rotl_optab,
-                                shifted,
-                                GEN_INT (GET_MODE_BITSIZE (mode)
-                                         - INTVAL (op1)),
-                                target, unsignedp, methods);
        }
       else if (unsignedp)
        temp = expand_binop (mode,
index 31212cbc007f4056318cc3ad2f6d3c27ec3e0697..bc859205279639f69ac1f1be276db52c83719e8d 100644 (file)
@@ -1049,6 +1049,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
                  || binoptab->code == ROTATERT);
   rtx entry_last = get_last_insn ();
   rtx last;
+  bool first_pass_p;
 
   class = GET_MODE_CLASS (mode);
 
@@ -1098,6 +1099,8 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
        }
     }
 
+ retry:
+
   /* If we can do it with a three-operand insn, do so.  */
 
   if (methods != OPTAB_MUST_WIDEN
@@ -1183,6 +1186,22 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
        delete_insns_since (last);
     }
 
+  /* If we were trying to rotate by a constant value, and that didn't
+     work, try rotating the other direction before falling back to
+     shifts and bitwise-or.  */
+  if (first_pass_p
+      && (binoptab == rotl_optab || binoptab == rotr_optab)
+      && class == MODE_INT
+      && GET_CODE (op1) == CONST_INT
+      && INTVAL (op1) > 0
+      && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
+    {
+      first_pass_p = false;
+      op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
+      binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab;
+      goto retry;
+    }
+
   /* If this is a multiply, see if we can do a widening operation that
      takes operands of this mode and makes a wider mode.  */