aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKazu Hirata <kazu@hxi.com>2000-08-11 01:43:47 +0000
committerJeff Law <law@gcc.gnu.org>2000-08-10 19:43:47 -0600
commitedd71f0f6cd9a303874d4a3e604a5f5fe760a975 (patch)
treefaabefbb5aa1ec913af93e5ae0128448ac55d82f
parentdff55dbc71b08ecca61d1069f386d080ab9dbd0d (diff)
downloadgcc-edd71f0f6cd9a303874d4a3e604a5f5fe760a975.zip
gcc-edd71f0f6cd9a303874d4a3e604a5f5fe760a975.tar.gz
gcc-edd71f0f6cd9a303874d4a3e604a5f5fe760a975.tar.bz2
h8300.c (expand_a_rotate): New.
* 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
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/config/h8300/h8300-protos.h2
-rw-r--r--gcc/config/h8300/h8300.c222
-rw-r--r--gcc/config/h8300/h8300.md52
4 files changed, 288 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5b49d31..570ba13 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -13,6 +13,18 @@
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.
diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h
index d5d460b..d8e4e69 100644
--- a/gcc/config/h8300/h8300-protos.h
+++ b/gcc/config/h8300/h8300-protos.h
@@ -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[]));
diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c
index e6e4bb7..3e82088 100644
--- a/gcc/config/h8300/h8300.c
+++ b/gcc/config/h8300/h8300.c
@@ -2662,6 +2662,177 @@ emit_a_shift (insn, operands)
}
}
+/* 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 "";
+}
+
/* 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;
}
diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md
index b8731f8..8b9c95e 100644
--- a/gcc/config/h8300/h8300.md
+++ b/gcc/config/h8300/h8300.md
@@ -1882,6 +1882,58 @@
[(set_attr "length" "20")
(set_attr "cc" "clobber")])
+;; ----------------------------------------------------------------------
+;; 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")])
+
;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------