From edd71f0f6cd9a303874d4a3e604a5f5fe760a975 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Fri, 11 Aug 2000 01:43:47 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 12 ++ gcc/config/h8300/h8300-protos.h | 2 + gcc/config/h8300/h8300.c | 222 ++++++++++++++++++++++++++++++++ gcc/config/h8300/h8300.md | 52 ++++++++ 4 files changed, 288 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5b49d311167..570ba13601d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -13,6 +13,18 @@ 2000-08-10 Kazu Hirata + * 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 d5d460b03c4..d8e4e69ffbb 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 e6e4bb7f9bc..3e820883082 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 b8731f895f5..8b9c95e21c8 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 ;; ----------------------------------------------------------------- -- 2.30.2