summaryrefslogtreecommitdiff
path: root/gcc/config/h8300
diff options
context:
space:
mode:
authorkazu <kazu@138bc75d-0d04-0410-961f-82ee72b054a4>2002-03-02 17:20:01 +0000
committerkazu <kazu@138bc75d-0d04-0410-961f-82ee72b054a4>2002-03-02 17:20:01 +0000
commit484c1e8df39bc80d8aa1664a297cf5c6158f00ca (patch)
tree54c6e2d0a349c41af52b457e632cb273d545b2a4 /gcc/config/h8300
parenta262ec1fcc35ebb63c307f5878a1ad561068be61 (diff)
downloadgcc-484c1e8df39bc80d8aa1664a297cf5c6158f00ca.tar.gz
* config/h8300/h8300-protos.h: Add a prototype for
compute_a_shift_length. * config/h8300/h8300.c (h8300_asm_insn_count): New. (compute_a_shift_length): Likewise. (h8300_adjust_insn_length): Do not adjust insn length of shift insns. * config/h8300/h8300.md (anonymous shift patterns): Use compute_a_shift_length. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@50227 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/h8300')
-rw-r--r--gcc/config/h8300/h8300-protos.h1
-rw-r--r--gcc/config/h8300/h8300.c199
-rw-r--r--gcc/config/h8300/h8300.md9
3 files changed, 162 insertions, 47 deletions
diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h
index ff31530dec9..c86484296cb 100644
--- a/gcc/config/h8300/h8300-protos.h
+++ b/gcc/config/h8300/h8300-protos.h
@@ -27,6 +27,7 @@ Boston, MA 02111-1307, USA. */
/* Declarations for functions used in insn-output.c. */
#ifdef RTX_CODE
extern const char *output_a_shift PARAMS ((rtx *));
+extern unsigned int compute_a_shift_length PARAMS ((rtx, rtx *));
extern const char *emit_a_rotate PARAMS ((enum rtx_code, rtx *));
extern const char *output_simode_bld PARAMS ((int, rtx[]));
extern void print_operand_address PARAMS ((FILE *, rtx));
diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c
index aa31531e6b9..456577a7a76 100644
--- a/gcc/config/h8300/h8300.c
+++ b/gcc/config/h8300/h8300.c
@@ -54,6 +54,7 @@ static unsigned int compute_saved_regs PARAMS ((void));
static void push PARAMS ((FILE *, int));
static void pop PARAMS ((FILE *, int));
static const char *cond_string PARAMS ((enum rtx_code));
+static unsigned int h8300_asm_insn_count PARAMS ((const char *));
const struct attribute_spec h8300_attribute_table[];
static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *));
@@ -2863,6 +2864,160 @@ output_a_shift (operands)
}
}
}
+
+static unsigned int
+h8300_asm_insn_count (const char *template)
+{
+ unsigned int count = 1;
+
+ for (; *template; template++)
+ if (*template == '\n')
+ count++;
+
+ return count;
+}
+
+unsigned int
+compute_a_shift_length (insn, operands)
+ rtx insn ATTRIBUTE_UNUSED;
+ rtx *operands;
+{
+ rtx shift = operands[3];
+ enum machine_mode mode = GET_MODE (shift);
+ enum rtx_code code = GET_CODE (shift);
+ enum shift_type shift_type;
+ enum shift_mode shift_mode;
+ struct shift_info info;
+ unsigned int wlength = 0;
+
+ switch (mode)
+ {
+ case QImode:
+ shift_mode = QIshift;
+ break;
+ case HImode:
+ shift_mode = HIshift;
+ break;
+ case SImode:
+ shift_mode = SIshift;
+ break;
+ default:
+ abort ();
+ }
+
+ switch (code)
+ {
+ case ASHIFTRT:
+ shift_type = SHIFT_ASHIFTRT;
+ break;
+ case LSHIFTRT:
+ shift_type = SHIFT_LSHIFTRT;
+ break;
+ case ASHIFT:
+ shift_type = SHIFT_ASHIFT;
+ break;
+ default:
+ abort ();
+ }
+
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ /* Get the assembler code to do one shift. */
+ get_shift_alg (shift_type, shift_mode, 1, &info);
+
+ return (4 + h8300_asm_insn_count (info.shift1)) * 2;
+ }
+ else
+ {
+ int n = INTVAL (operands[2]);
+
+ /* If the count is negative, make it 0. */
+ if (n < 0)
+ n = 0;
+ /* If the count is too big, truncate it.
+ ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to
+ do the intuitive thing. */
+ else if ((unsigned int) n > GET_MODE_BITSIZE (mode))
+ n = GET_MODE_BITSIZE (mode);
+
+ get_shift_alg (shift_type, shift_mode, n, &info);
+
+ switch (info.alg)
+ {
+ case SHIFT_SPECIAL:
+ wlength += h8300_asm_insn_count (info.special);
+ /* Fall through. */
+
+ case SHIFT_INLINE:
+ n = info.remainder;
+
+ if (info.shift2 != NULL)
+ {
+ wlength += h8300_asm_insn_count (info.shift2) * (n / 2);
+ n = n % 2;
+ }
+
+ wlength += h8300_asm_insn_count (info.shift1) * n;
+
+ return 2 * wlength;
+
+ case SHIFT_ROT_AND:
+ {
+ int m = GET_MODE_BITSIZE (mode) - n;
+
+ /* Not all possibilities of rotate are supported. They shouldn't
+ be generated, but let's watch for 'em. */
+ if (info.shift1 == 0)
+ abort ();
+
+ if (info.shift2 != NULL)
+ {
+ wlength += h8300_asm_insn_count (info.shift2) * (m / 2);
+ m = m % 2;
+ }
+
+ wlength += h8300_asm_insn_count (info.shift1) * m;
+
+ /* Now mask off the high bits. */
+ switch (mode)
+ {
+ case QImode:
+ wlength += 1;
+ break;
+ case HImode:
+ wlength += 2;
+ break;
+ case SImode:
+ if (TARGET_H8300)
+ abort ();
+ wlength += 3;
+ break;
+ default:
+ abort ();
+ }
+ return 2 * wlength;
+ }
+
+ case SHIFT_LOOP:
+ /* A loop to shift by a "large" constant value.
+ If we have shift-by-2 insns, use them. */
+ if (info.shift2 != NULL)
+ {
+ wlength += 3 + h8300_asm_insn_count (info.shift2);
+ if (n % 2)
+ wlength += h8300_asm_insn_count (info.shift1);
+ }
+ else
+ {
+ wlength += 3 + h8300_asm_insn_count (info.shift1);
+ }
+ return 2 * wlength;
+
+ default:
+ abort ();
+ }
+ }
+}
/* 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,
@@ -3436,50 +3591,6 @@ h8300_adjust_insn_length (insn, length)
}
}
- /* Shifts need various adjustments. */
- if (GET_CODE (pat) == PARALLEL
- && GET_CODE (XVECEXP (pat, 0, 0)) == SET
- && (GET_CODE (SET_SRC (XVECEXP (pat, 0, 0))) == ASHIFTRT
- || GET_CODE (SET_SRC (XVECEXP (pat, 0, 0))) == LSHIFTRT
- || GET_CODE (SET_SRC (XVECEXP (pat, 0, 0))) == ASHIFT))
- {
- rtx src = SET_SRC (XVECEXP (pat, 0, 0));
- enum machine_mode mode = GET_MODE (src);
- int shift;
-
- if (GET_CODE (XEXP (src, 1)) != CONST_INT)
- return 0;
-
- shift = INTVAL (XEXP (src, 1));
- /* According to ANSI, negative shift is undefined. It is
- considered to be zero in this case (see function
- output_a_shift above). */
- if (shift < 0)
- shift = 0;
-
- /* QImode shifts by small constants take one insn
- per shift. So the adjustment is 20 (md length) -
- # shifts * 2. */
- if (mode == QImode && shift <= 4)
- return -(20 - shift * 2);
-
- /* Similarly for HImode and SImode shifts by small constants on
- the H8/300H and H8/S. */
- if ((TARGET_H8300H || TARGET_H8300S)
- && (mode == HImode || mode == SImode) && shift <= 4)
- return -(20 - shift * 2);
-
- /* HImode shifts by small constants for the H8/300. */
- if (mode == HImode && shift <= 4)
- return -(20 - (shift * (GET_CODE (src) == ASHIFT ? 2 : 4)));
-
- /* SImode shifts by small constants for the H8/300. */
- if (mode == SImode && shift <= 2)
- return -(20 - (shift * (GET_CODE (src) == ASHIFT ? 6 : 8)));
-
- /* XXX ??? Could check for more shift/rotate cases here. */
- }
-
/* Rotations need various adjustments. */
if (GET_CODE (pat) == SET
&& (GET_CODE (SET_SRC (pat)) == ROTATE
diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md
index b17d5557944..a3c445a9396 100644
--- a/gcc/config/h8300/h8300.md
+++ b/gcc/config/h8300/h8300.md
@@ -1769,7 +1769,8 @@
(clobber (match_scratch:QI 4 "=X,&r"))]
""
"* return output_a_shift (operands);"
- [(set_attr "length" "20")
+ [(set (attr "length")
+ (symbol_ref "compute_a_shift_length (insn, operands)"))
(set_attr "cc" "clobber")])
;; HI BIT SHIFTS
@@ -1803,7 +1804,8 @@
(clobber (match_scratch:QI 4 "=X,&r"))]
""
"* return output_a_shift (operands);"
- [(set_attr "length" "20")
+ [(set (attr "length")
+ (symbol_ref "compute_a_shift_length (insn, operands)"))
(set_attr "cc" "clobber")])
;; SI BIT SHIFTS
@@ -1837,7 +1839,8 @@
(clobber (match_scratch:QI 4 "=X,&r"))]
""
"* return output_a_shift (operands);"
- [(set_attr "length" "20")
+ [(set (attr "length")
+ (symbol_ref "compute_a_shift_length (insn, operands)"))
(set_attr "cc" "clobber")])
;; ----------------------------------------------------------------------