* config/i386/i386.md (bswapsi_1): Rename from bswapsi2,
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Feb 2007 16:42:12 +0000 (16:42 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Feb 2007 16:42:12 +0000 (16:42 +0000)
        remove flags clobber.
        (bswapsi2): New expander, emit code for !TARGET_BSWAP.
        (bswaphi_lowpart): New.
        (bswapdi2): Rename from bswapdi2_rex, remove flags clobber,
        remove TARGET_BSWAP test.  Delete expander of the same name.

        * optabs.c (widen_bswap, expand_doubleword_bswap): New.
        (expand_unop): Use them.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121884 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 7702816..96ff9ac 100644 (file)
@@ -1,3 +1,15 @@
+2007-02-13  Richard Henderson  <rth@redhat.com>
+
+       * config/i386/i386.md (bswapsi_1): Rename from bswapsi2,
+       remove flags clobber.
+       (bswapsi2): New expander, emit code for !TARGET_BSWAP.
+       (bswaphi_lowpart): New.
+       (bswapdi2): Rename from bswapdi2_rex, remove flags clobber,
+       remove TARGET_BSWAP test.  Delete expander of the same name.
+
+       * optabs.c (widen_bswap, expand_doubleword_bswap): New.
+       (expand_unop): Use them.
+
 2007-02-13  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/i386.md (cmpdi_ccno_1_rex64, *cmpsi_ccno_1,
index 488005b..0b529c2 100644 (file)
    (set_attr "type" "bitmanip")
    (set_attr "mode" "SI")])
 
-(define_insn "bswapsi2"
+(define_expand "bswapsi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (bswap:SI (match_operand:SI 1 "register_operand" "")))]
+  ""
+{
+  if (!TARGET_BSWAP)
+    {
+      rtx x = operands[0];
+
+      emit_move_insn (x, operands[1]);
+      emit_insn (gen_bswaphi_lowpart (gen_lowpart (HImode, x)));
+      emit_insn (gen_rotlsi3 (x, x, GEN_INT (16)));
+      emit_insn (gen_bswaphi_lowpart (gen_lowpart (HImode, x)));
+      DONE;
+    }
+})
+
+(define_insn "*bswapsi_1"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (bswap:SI (match_operand:SI 1 "register_operand" "0")))
-   (clobber (reg:CC FLAGS_REG))]
+       (bswap:SI (match_operand:SI 1 "register_operand" "0")))]
   "TARGET_BSWAP"
-  "bswap\t%k0"
+  "bswap\t%0"
   [(set_attr "prefix_0f" "1")
    (set_attr "length" "2")])
 
-(define_insn "*bswapdi2_rex"
+(define_insn "bswaphi_lowpart"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+Q"))
+       (bswap:HI (match_dup 0)))]
+  ""
+  "xchg{b}\t%h0, %b0"
+  [(set_attr "type" "alu1")
+   (set_attr "mode" "QI")
+   (set_attr "pent_pair" "np")
+   (set_attr "athlon_decode" "vector")
+   (set_attr "amdfam10_decode" "double")])
+
+(define_insn "bswapdi2"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (bswap:DI (match_operand:DI 1 "register_operand" "0")))
-   (clobber (reg:CC FLAGS_REG))]
-  "TARGET_64BIT && TARGET_BSWAP"
+       (bswap:DI (match_operand:DI 1 "register_operand" "0")))]
+  "TARGET_64BIT"
   "bswap\t%0"
   [(set_attr "prefix_0f" "1")
    (set_attr "length" "3")])
 
-(define_expand "bswapdi2"
-  [(parallel [(set (match_operand:DI 0 "register_operand" "")
-                  (bswap:DI (match_operand:DI 1 "register_operand" "")))
-             (clobber (reg:CC FLAGS_REG))])]
-  "TARGET_BSWAP"
-  {
-    if (!TARGET_64BIT)
-      {
-       rtx tmp1, tmp2;
-       tmp1 = gen_reg_rtx (SImode);
-       tmp2 = gen_reg_rtx (SImode);
-       emit_insn (gen_bswapsi2 (tmp1, gen_lowpart (SImode, operands[1])));
-       emit_insn (gen_bswapsi2 (tmp2, gen_highpart (SImode, operands[1])));
-       emit_move_insn (gen_lowpart (SImode, operands[0]), tmp2);
-       emit_move_insn (gen_highpart (SImode, operands[0]), tmp1);
-       DONE;
-      }
-  })
-
 (define_expand "clzdi2"
   [(parallel
      [(set (match_operand:DI 0 "register_operand" "")
index e66c115..c8ec9ef 100644 (file)
@@ -2401,6 +2401,73 @@ widen_clz (enum machine_mode mode, rtx op0, rtx target)
   return 0;
 }
 
+/* Try calculating
+       (bswap:narrow x)
+   as
+       (lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow))).  */
+static rtx
+widen_bswap (enum machine_mode mode, rtx op0, rtx target)
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  enum machine_mode wider_mode;
+  rtx x, last;
+
+  if (!CLASS_HAS_WIDER_MODES_P (class))
+    return NULL_RTX;
+
+  for (wider_mode = GET_MODE_WIDER_MODE (mode);
+       wider_mode != VOIDmode;
+       wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+    if (bswap_optab->handlers[wider_mode].insn_code != CODE_FOR_nothing)
+      goto found;
+  return NULL_RTX;
+
+ found:
+  last = get_last_insn ();
+
+  x = widen_operand (op0, wider_mode, mode, true, true);
+  x = expand_unop (wider_mode, bswap_optab, x, NULL_RTX, true);
+
+  if (x != 0)
+    x = expand_shift (RSHIFT_EXPR, wider_mode, x,
+                     size_int (GET_MODE_BITSIZE (wider_mode)
+                               - GET_MODE_BITSIZE (mode)),
+                     NULL_RTX, true);
+
+  if (x != 0)
+    {
+      if (target == 0)
+       target = gen_reg_rtx (mode);
+      emit_move_insn (target, gen_lowpart (mode, x));
+    }
+  else
+    delete_insns_since (last);
+
+  return target;
+}
+
+/* Try calculating bswap as two bswaps of two word-sized operands.  */
+
+static rtx
+expand_doubleword_bswap (enum machine_mode mode, rtx op, rtx target)
+{
+  rtx t0, t1;
+
+  t1 = expand_unop (word_mode, bswap_optab,
+                   operand_subword_force (op, 0, mode), NULL_RTX, true);
+  t0 = expand_unop (word_mode, bswap_optab,
+                   operand_subword_force (op, 1, mode), NULL_RTX, true);
+
+  if (target == 0)
+    target = gen_reg_rtx (mode);
+  if (REG_P (target))
+    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+  emit_move_insn (operand_subword (target, 0, 1, mode), t0);
+  emit_move_insn (operand_subword (target, 1, 1, mode), t1);
+
+  return target;
+}
+
 /* Try calculating (parity x) as (and (popcount x) 1), where
    popcount can also be done in a wider mode.  */
 static rtx
@@ -2639,9 +2706,23 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
        goto try_libcall;
     }
 
-  /* We can't widen a bswap.  */
+  /* Widening (or narrowing) bswap needs special treatment.  */
   if (unoptab == bswap_optab)
-    goto try_libcall;
+    {
+      temp = widen_bswap (mode, op0, target);
+      if (temp)
+       return temp;
+
+      if (GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
+         && unoptab->handlers[word_mode].insn_code != CODE_FOR_nothing)
+       {
+         temp = expand_doubleword_bswap (mode, op0, target);
+         if (temp)
+           return temp;
+       }
+
+      goto try_libcall;
+    }
 
   if (CLASS_HAS_WIDER_MODES_P (class))
     for (wider_mode = GET_MODE_WIDER_MODE (mode);