h8300.c (expand_a_rotate): New.
authorKazu Hirata <kazu@hxi.com>
Fri, 11 Aug 2000 01:43:47 +0000 (01:43 +0000)
committerJeff Law <law@gcc.gnu.org>
Fri, 11 Aug 2000 01:43:47 +0000 (19:43 -0600)
        * h8300.c (expand_a_rotate): New.
        (emit_a_rotate): Likewise.
        (h8300_adjust_insn_length): Add support for the rotate insns.
        * h8300.md (rotlqi3): New.
        (*rotlqi3_1): Likewise.
        (rotlhi3): Likewise.
        (*rotlhi3_1): Likewise.
        (rotlhi3): Likewise.
        (*rotlhi3_1): Likewise.
        * h8300-proto.h: Add prototypes for expand_a_rotate and
        emit_a_rotate.

From-SVN: r35616

gcc/ChangeLog
gcc/config/h8300/h8300-protos.h
gcc/config/h8300/h8300.c
gcc/config/h8300/h8300.md

index 5b49d3111679bd21f34347be210ec59df301f4d1..570ba13601d0f7cd903f55d0cfa7e310111c8223 100644 (file)
 
 2000-08-10  Kazu Hirata  <kazu@hxi.com>
 
+        * h8300.c (expand_a_rotate): New.
+        (emit_a_rotate): Likewise.
+        (h8300_adjust_insn_length): Add support for the rotate insns.
+        * h8300.md (rotlqi3): New.
+        (*rotlqi3_1): Likewise.
+        (rotlhi3): Likewise.
+        (*rotlhi3_1): Likewise.
+        (rotlhi3): Likewise.
+        (*rotlhi3_1): Likewise.
+        * h8300-proto.h: Add prototypes for expand_a_rotate and
+        emit_a_rotate.
+
        * h8300.c: Fix comment typos.
        (dosize): Declare the variable amount as unsigned.
        (get_shift_alg): Fix a comparison between signed and unsigned.
index d5d460b03c4f192f9dd0c1b5d62fe7b858142cb4..d8e4e69ffbbb9ab006a0e7c30abe8dbd3fd3f3fe 100644 (file)
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA.  */
 /* Declarations for functions used in insn-output.c.  */
 #ifdef RTX_CODE
 extern const char *emit_a_shift PARAMS ((rtx, rtx *));
+extern const char *emit_a_rotate PARAMS ((int, rtx *));
 extern const char *output_adds_subs PARAMS ((rtx *));
 extern const char *output_simode_bld PARAMS ((int, int, rtx[]));
 extern void print_operand_address PARAMS ((FILE *, rtx));
@@ -34,6 +35,7 @@ extern void final_prescan_insn PARAMS ((rtx, rtx *, int));
 extern int do_movsi PARAMS ((rtx[]));
 extern void notice_update_cc PARAMS ((rtx, rtx));
 extern int expand_a_shift PARAMS ((enum machine_mode, int, rtx[]));
+extern int expand_a_rotate PARAMS ((int, rtx[]));
 extern int fix_bit_operand PARAMS ((rtx *, int, enum rtx_code));
 extern int h8300_adjust_insn_length PARAMS ((rtx, int));
 extern void split_adds_subs PARAMS ((enum machine_mode, rtx[]));
index e6e4bb7f9bcf4905f334485c2647612a3e95dc0d..3e8208830822e68d6974228b7ee34b9040fe4a20 100644 (file)
@@ -2662,6 +2662,177 @@ emit_a_shift (insn, operands)
     }
 }
 \f
+/* A rotation by a non-constant will cause a loop to be generated, in
+   which a rotation by one bit is used.  A rotation by a constant,
+   including the one in the loop, will be taken care of by
+   emit_a_rotate () at the insn emit time.  */
+
+int
+expand_a_rotate (code, operands)
+     int code;
+     rtx operands[];
+{
+  rtx dst = operands[0];
+  rtx src = operands[1];
+  rtx rotate_amount = operands[2];
+  enum machine_mode mode = GET_MODE (dst);
+  rtx tmp;
+
+  /* We rotate in place.  */
+  emit_move_insn (dst, src);
+
+  if (GET_CODE (rotate_amount) != CONST_INT)
+    {
+      rtx counter = gen_reg_rtx (QImode);
+      rtx start_label = gen_label_rtx ();
+      rtx end_label = gen_label_rtx ();
+
+      /* If the rotate amount is less than or equal to 0,
+        we go out of the loop.  */
+      emit_cmp_and_jump_insns (rotate_amount, GEN_INT (0),
+                              LE, NULL_RTX, QImode, 0, 0, end_label);
+
+      /* Initialize the loop counter.  */
+      emit_move_insn (counter, rotate_amount);
+
+      emit_label (start_label);
+
+      /* Rotate by one bit.  */
+      tmp = gen_rtx (code, mode, dst, GEN_INT (1));
+      emit_insn (gen_rtx_SET (mode, dst, tmp));
+
+      /* Decrement the counter by 1.  */
+      tmp = gen_rtx_PLUS (QImode, counter, GEN_INT (-1));
+      emit_insn (gen_rtx_SET (VOIDmode, counter, tmp));
+
+      /* If the loop counter is non-zero, we go back to the beginning
+        of the loop.  */
+      emit_cmp_and_jump_insns (counter, GEN_INT (0),
+                              NE, NULL_RTX, QImode, 1, 0, start_label);
+
+      emit_label (end_label);
+    }
+  else
+    {
+      /* Rotate by AMOUNT bits.  */
+      tmp = gen_rtx (code, mode, dst, rotate_amount);
+      emit_insn (gen_rtx_SET (mode, dst, tmp));
+    }
+
+  return 1;
+}
+
+/* Emit rotate insns.  */
+
+const char *
+emit_a_rotate (code, operands)
+     int code;
+     rtx *operands;
+{
+  rtx dst = operands[0];
+  rtx rotate_amount = operands[2];
+  enum shift_mode rotate_mode;
+  enum shift_type rotate_type;
+  const char *insn_buf;
+  int bits;
+  int amount;
+  enum machine_mode mode = GET_MODE (dst);
+
+  if (GET_CODE (rotate_amount) != CONST_INT)
+    abort ();
+
+  switch (mode)
+    {
+    case QImode:
+      rotate_mode = QIshift;
+      break;
+    case HImode:
+      rotate_mode = HIshift;
+      break;
+    case SImode:
+      rotate_mode = SIshift;
+      break;
+    default:
+      abort ();
+    }
+
+  switch (code)
+    {
+    case ROTATERT:
+      rotate_type = SHIFT_ASHIFT;
+      break;
+    case ROTATE:
+      rotate_type = SHIFT_LSHIFTRT;
+      break;
+    default:
+      abort ();
+    }
+
+  amount = INTVAL (rotate_amount);
+
+  /* Clean up AMOUNT.  */
+  if (amount < 0)
+    amount = 0;
+  if ((unsigned int) amount > GET_MODE_BITSIZE (mode))
+    amount = GET_MODE_BITSIZE (mode);
+
+  /* Determine the faster direction.  After this phase, amount will be
+     at most a half of GET_MODE_BITSIZE (mode).  */
+  if ((unsigned int) amount > GET_MODE_BITSIZE (mode) / 2)
+    {
+      /* Flip the direction.  */
+      amount = GET_MODE_BITSIZE (mode) - amount;
+      rotate_type =
+       (rotate_type == SHIFT_ASHIFT) ? SHIFT_LSHIFTRT : SHIFT_ASHIFT;
+    }
+
+  /* See if a byte swap (in HImode) or a word swap (in SImode) can
+     boost up the rotation.  */
+  if ((mode == HImode && TARGET_H8300 && amount >= 5)
+      || (mode == HImode && TARGET_H8300H && amount >= 6)
+      || (mode == HImode && TARGET_H8300S && amount == 8)
+      || (mode == SImode && TARGET_H8300H && amount >= 10)
+      || (mode == SImode && TARGET_H8300S && amount >= 13))
+    {
+      switch (mode)
+       {
+       case HImode:
+         /* This code works on any family.  */
+         insn_buf = "xor.b\t%s0,%t0\n\txor.b\t%t0,%s0\n\txor.b\t%s0,%t0";
+         output_asm_insn (insn_buf, operands);
+         break;
+
+       case SImode:
+         /* This code works on the H8/300H and H8/S.  */
+         insn_buf = "xor.w\t%e0,%f0\n\txor.w\t%f0,%e0\n\txor.w\t%e0,%f0";
+         output_asm_insn (insn_buf, operands);
+         break;
+
+       default:
+         abort ();
+       }
+
+      /* Adjust AMOUNT and flip the direction.  */
+      amount = GET_MODE_BITSIZE (mode) / 2 - amount;
+      rotate_type =
+       (rotate_type == SHIFT_ASHIFT) ? SHIFT_LSHIFTRT : SHIFT_ASHIFT;
+    }
+
+  /* Emit rotate insns.  */
+  for (bits = TARGET_H8300S ? 2 : 1; bits > 0; bits /= 2)
+    {
+      if (bits == 2)
+       insn_buf = rotate_two[rotate_type][rotate_mode];
+      else
+       insn_buf = rotate_one[cpu_type][rotate_type][rotate_mode];
+      
+      for (; amount >= bits; amount -= bits)
+       output_asm_insn (insn_buf, operands);
+    }
+
+  return "";
+}
+\f
 /* Fix the operands of a gen_xxx so that it could become a bit
   operating insn.  */
 
@@ -3052,5 +3223,56 @@ h8300_adjust_insn_length (insn, length)
       /* XXX ??? Could check for more shift/rotate cases here.  */
     }
 
+  /* Rotations need various adjustments.  */
+  if (GET_CODE (pat) == SET
+      && (GET_CODE (SET_SRC (pat)) == ROTATE
+         || GET_CODE (SET_SRC (pat)) == ROTATERT))
+    {
+      rtx src = SET_SRC (pat);
+      enum machine_mode mode = GET_MODE (src);
+      int amount;
+      int states = 0;
+
+      if (GET_CODE (XEXP (src, 1)) != CONST_INT)
+       return 0;
+
+      amount = INTVAL (XEXP (src, 1));
+
+      /* Clean up AMOUNT.  */
+      if (amount < 0)
+       amount = 0;
+      if ((unsigned int) amount > GET_MODE_BITSIZE (mode))
+       amount = GET_MODE_BITSIZE (mode);
+
+      /* Determine the faster direction.  After this phase, amount
+        will be at most a half of GET_MODE_BITSIZE (mode).  */
+      if ((unsigned int) amount > GET_MODE_BITSIZE (mode) / 2)
+       /* Flip the direction.  */
+       amount = GET_MODE_BITSIZE (mode) - amount;
+
+      /* See if a byte swap (in HImode) or a word swap (in SImode) can
+        boost up the rotation.  */
+      if ((mode == HImode && TARGET_H8300 && amount >= 5)
+         || (mode == HImode && TARGET_H8300H && amount >= 6)
+         || (mode == HImode && TARGET_H8300S && amount == 8)
+         || (mode == SImode && TARGET_H8300H && amount >= 10)
+         || (mode == SImode && TARGET_H8300S && amount >= 13))
+       {
+         /* Adjust AMOUNT and flip the direction.  */
+         amount = GET_MODE_BITSIZE (mode) / 2 - amount;
+         states += 6;
+       }
+
+      /* We use 2-bit rotatations on the H8/S.  */
+      if (TARGET_H8300S)
+       amount = amount / 2 + amount % 2;
+
+      /* The H8/300 uses three insns to rotate one bit, taking 6
+         states.  */
+      states += amount * ((TARGET_H8300 && mode == HImode) ? 6 : 2);
+
+      return -(20 - states);
+    }
+
   return 0;
 }
index b8731f895f53cf5491ccedf4a9ef933e7d51c5ae..8b9c95e21c8af4e8938590f2bb1e84068d52c444 100644 (file)
   [(set_attr "length" "20")
    (set_attr "cc" "clobber")])
 \f
+;; ----------------------------------------------------------------------
+;; ROTATIONS
+;; ----------------------------------------------------------------------
+
+(define_expand "rotlqi3"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (rotate:QI (match_operand:QI 1 "register_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))]
+  ""
+  "if (expand_a_rotate (ROTATE, operands)) DONE;else FAIL;")
+
+(define_insn "*rotlqi3_1"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (rotate:QI (match_operand:QI 1 "register_operand" "0")
+                  (match_operand:QI 2 "immediate_operand" "")))]
+  ""
+  "* return emit_a_rotate (ROTATE, operands);"
+  [(set_attr "length" "20")
+   (set_attr "cc" "clobber")])
+
+(define_expand "rotlhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (rotate:HI (match_operand:HI 1 "register_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))]
+  ""
+  "if (expand_a_rotate (ROTATE, operands)) DONE;else FAIL;")
+
+(define_insn "*rotlhi3_1"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (rotate:HI (match_operand:HI 1 "register_operand" "0")
+                  (match_operand:QI 2 "immediate_operand" "")))]
+  ""
+  "* return emit_a_rotate (ROTATE, operands);"
+  [(set_attr "length" "20")
+   (set_attr "cc" "clobber")])
+
+(define_expand "rotlsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (rotate:SI (match_operand:SI 1 "register_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "if (expand_a_rotate (ROTATE, operands)) DONE;else FAIL;")
+
+(define_insn "*rotlsi3_1"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (rotate:SI (match_operand:SI 1 "register_operand" "0")
+                  (match_operand:QI 2 "immediate_operand" "")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "* return emit_a_rotate (ROTATE, operands);"
+  [(set_attr "length" "20")
+   (set_attr "cc" "clobber")])
+\f
 ;; -----------------------------------------------------------------
 ;; BIT FIELDS
 ;; -----------------------------------------------------------------