summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormeissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4>1998-04-28 05:58:21 +0000
committermeissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4>1998-04-28 05:58:21 +0000
commit868d8e325a85ea4e1ecdde63a135e509f5fdf1bf (patch)
treef579abf03a73032cbc0ea682d5503777e1313833
parent803e9d57a1db9585a73a483d8f99ba4872168f29 (diff)
downloadppe42-gcc-868d8e325a85ea4e1ecdde63a135e509f5fdf1bf.tar.gz
ppe42-gcc-868d8e325a85ea4e1ecdde63a135e509f5fdf1bf.zip
update m32r port
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@19465 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog57
-rw-r--r--gcc/config/m32r/m32r.c494
-rw-r--r--gcc/config/m32r/m32r.h223
-rw-r--r--gcc/config/m32r/m32r.md305
-rw-r--r--gcc/config/m32r/t-m32r2
-rwxr-xr-xgcc/configure2
-rw-r--r--gcc/configure.in2
7 files changed, 941 insertions, 144 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d9e7a7fb0dc..5c1fd17e1bb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,60 @@
+Tue Apr 28 08:55:26 1998 Michael Meissner <meissner@cygnus.com>
+
+ * m32r.c (*_oper{and|ator}): Change enum arguments and return
+ values to int, so they can be prototyped even in files that don't
+ include rtl.h.
+ ({small,large}_insn_p): Ditto.
+ (m32r_select_cc_mode): Ditto.
+ (gen_compare): Ditto.
+ (function_arg_partial_nregs): Ditto.
+ (m32r_setup_incoming_varargs): Ditto.
+ (init_reg_tables): Add prototype.
+ (m32r_frame_info): Add prolog_size field.
+ (m32r_compute_frame_size): Calculate the size of the prologue.
+ (m32r_first_insn_address): Return prologue size.
+ (m32r_output_function_prologue): Calculate frame size before
+ printing out information. Print out the prologue size.
+
+ * m32r.h: Prototype all functions in m32r.c.
+ (FIRST_INSN_ADDRESS): Declare, returning prologue size.
+
+ * m32r.md (bcc functions): Cast enum's to int.
+
+ * m32r.c (conditional_move_operand): Silence a debug message.
+ ({small,long}_insn): New predicates.
+
+ * m32r.h (TARGET_M32R): New macro.
+ (PREDICATE_CODES): Rearrange somewhat, add small_insn/long_insn.
+ (HAIFA_P): Define as 1/0 depending on whether the Haifa scheduler
+ was selected.
+ (ISSUE_RATE): Define as 2.
+
+ * m32r.md (insn_size): New attribute.
+ ({,rev_}branch_insn): Add .s qualifier to branches believed to be
+ short.
+ (m32r): New attribute.
+
+ * configure.in (enable_haifa): Switch m32r to Haifa by default.
+ * configure: Regenerate.
+
+ (Changes from Nick Clifton <nickc@cygnus.com>)
+ * m32r.h (EXTRA_CONSTRAINT): Implement 'S' constraint to perfoirm
+ the equivalent of a negated 'I' constraint.
+ (PRESERVE_DEATH_INFO_REGNO_P): Define in order to allow peephole
+ optimisation to work.
+
+ * m32r.md (cmp_ne_small_const_insn): Use 'S' constriant rather
+ than 'I' since the value is negated.
+ (peephole): Add peephole optimisation to cope with optimization of
+ divide and subtracts of the same operands.
+
+ * m32r.c zero_and_one, emit_cond_move): Add support for MVFC.
+ * m32r.h: Ditto.
+ * m32r.md: Ditto.
+
+ * m32r.h (PREDICATE_CODES): Add declaration of machine specific
+ predicates.
+
Tue Apr 28 07:25:53 1998 Manfred Hollstein <manfred@s-direktnet.de>
* Makefile.in (libgcc2.ready): Revert last patch (Apr 24).
diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c
index 0b7b631d7b0..3f800578e5c 100644
--- a/gcc/config/m32r/m32r.c
+++ b/gcc/config/m32r/m32r.c
@@ -1,5 +1,5 @@
/* Subroutines used for code generation on the Mitsubishi M32R cpu.
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -41,8 +41,6 @@ rtx m32r_compare_op0, m32r_compare_op1;
/* Array of valid operand punctuation characters. */
char m32r_punct_chars[256];
-static void init_reg_tables ();
-
/* Selected code model. */
char *m32r_model_string = M32R_MODEL_DEFAULT;
enum m32r_model m32r_model;
@@ -51,6 +49,10 @@ enum m32r_model m32r_model;
char *m32r_sdata_string = M32R_SDATA_DEFAULT;
enum m32r_sdata m32r_sdata;
+
+/* Forward declaration. */
+static void init_reg_tables PROTO((void));
+
/* Called by OVERRIDE_OPTIONS to initialize various things. */
void
@@ -84,6 +86,7 @@ m32r_init ()
m32r_sdata = M32R_SDATA_USE;
else
error ("bad value (%s) for -msdata switch", m32r_sdata_string);
+
}
/* Vectors to keep interesting information about registers where it can easily
@@ -95,7 +98,8 @@ m32r_init ()
they all fit (as bit numbers) in a 32 bit word (again). Each real mode is
mapped into one m32r_mode_class mode. */
-enum m32r_mode_class {
+enum m32r_mode_class
+{
C_MODE,
S_MODE, D_MODE, T_MODE, O_MODE,
SF_MODE, DF_MODE, TF_MODE, OF_MODE
@@ -113,9 +117,11 @@ enum m32r_mode_class {
/* Modes for quad-word and smaller quantities. */
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
+
/* Value is 1 if register/mode pair is acceptable on arc. */
-unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] = {
+unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] =
+{
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES,
S_MODES, C_MODES
@@ -412,21 +418,23 @@ m32r_init_expanders ()
/* Acceptable arguments to the call insn. */
int
-call_address_operand (op, mode)
+call_address_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
- return symbolic_operand (op, mode);
+ return symbolic_operand (op, int_mode);
- /* Constants and values in registers are not OK, because
- the m32r BL instruction can only support PC relative branching. */
+/* Constants and values in registers are not OK, because
+ the m32r BL instruction can only support PC relative branching. */
}
int
-call_operand (op, mode)
+call_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
+
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
@@ -436,9 +444,9 @@ call_operand (op, mode)
/* Returns 1 if OP is a symbol reference. */
int
-symbolic_operand (op, mode)
+symbolic_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
switch (GET_CODE (op))
{
@@ -446,6 +454,7 @@ symbolic_operand (op, mode)
case LABEL_REF:
case CONST :
return 1;
+
default:
return 0;
}
@@ -454,9 +463,9 @@ symbolic_operand (op, mode)
/* Return 1 if OP is a reference to an object in .sdata/.sbss. */
int
-small_data_operand (op, mode)
+small_data_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (! TARGET_SDATA_USE)
return 0;
@@ -477,9 +486,9 @@ small_data_operand (op, mode)
/* Return 1 if OP is a symbol that can use 24 bit addressing. */
int
-addr24_operand (op, mode)
+addr24_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) == LABEL_REF)
return TARGET_ADDR24;
@@ -509,24 +518,24 @@ addr24_operand (op, mode)
/* Return 1 if OP is a symbol that needs 32 bit addressing. */
int
-addr32_operand (op, mode)
+addr32_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) == LABEL_REF)
return TARGET_ADDR32;
if (GET_CODE (op) == SYMBOL_REF)
- return (! addr24_operand (op)
- && ! small_data_operand (op));
+ return (! addr24_operand (op, int_mode)
+ && ! small_data_operand (op, int_mode));
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
{
- return (! addr24_operand (op)
- && ! small_data_operand (op));
+ return (! addr24_operand (op, int_mode)
+ && ! small_data_operand (op, int_mode));
}
return 0;
@@ -535,9 +544,9 @@ addr32_operand (op, mode)
/* Return 1 if OP is a function that can be called with the `bl' insn. */
int
-call26_operand (op, mode)
+call26_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) == SYMBOL_REF)
return ! LARGE_NAME_P (XSTR (op, 0));
@@ -548,9 +557,9 @@ call26_operand (op, mode)
/* Returns 1 if OP is an acceptable operand for seth/add3. */
int
-seth_add3_operand (op, mode)
+seth_add3_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) == SYMBOL_REF
|| GET_CODE (op) == LABEL_REF)
@@ -570,9 +579,9 @@ seth_add3_operand (op, mode)
useful in comparisons. */
int
-cmp_int16_operand (op, mode)
+cmp_int16_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) != CONST_INT)
return 0;
@@ -581,10 +590,10 @@ cmp_int16_operand (op, mode)
/* Return true if OP is an unsigned 16 bit immediate value. */
-static int
-uint16_operand (op, mode)
+int
+uint16_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) != CONST_INT)
return 0;
@@ -594,10 +603,12 @@ uint16_operand (op, mode)
/* Return true if OP is a register or signed 8 bit value. */
int
-reg_or_int16_operand (op, mode)
+reg_or_int16_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
+
if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT)
@@ -608,10 +619,12 @@ reg_or_int16_operand (op, mode)
/* Return true if OP is a register or an unsigned 16 bit value. */
int
-reg_or_uint16_operand (op, mode)
+reg_or_uint16_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
+
if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT)
@@ -622,10 +635,12 @@ reg_or_uint16_operand (op, mode)
/* Return true if OP is a register or signed 16 bit value for compares. */
int
-reg_or_cmp_int16_operand (op, mode)
+reg_or_cmp_int16_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
+
if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT)
@@ -636,9 +651,9 @@ reg_or_cmp_int16_operand (op, mode)
/* Return true if OP is a const_int requiring two instructions to load. */
int
-two_insn_const_operand (op, mode)
+two_insn_const_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
if (GET_CODE (op) != CONST_INT)
return 0;
@@ -653,15 +668,16 @@ two_insn_const_operand (op, mode)
move source. */
int
-move_src_operand (op, mode)
+move_src_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op))
{
case SYMBOL_REF :
case CONST :
- return addr24_operand (op, mode);
+ return addr24_operand (op, int_mode);
case CONST_INT :
/* ??? We allow more cse opportunities if we only allow constants
loadable with one insn, and split the rest into two. The instances
@@ -704,10 +720,11 @@ move_src_operand (op, mode)
move source. */
int
-move_double_src_operand (op, mode)
+move_double_src_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op))
{
case CONST_INT :
@@ -722,7 +739,7 @@ move_double_src_operand (op, mode)
/* (subreg (mem ...) ...) can occur here if the inner part was once a
pseudo-reg and is now a stack slot. */
if (GET_CODE (SUBREG_REG (op)) == MEM)
- return move_double_src_operand (SUBREG_REG (op), mode);
+ return move_double_src_operand (SUBREG_REG (op), int_mode);
else
return register_operand (op, mode);
case MEM :
@@ -739,10 +756,11 @@ move_double_src_operand (op, mode)
/* Return true if OP is an acceptable argument for a move destination. */
int
-move_dest_operand (op, mode)
+move_dest_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op))
{
case REG :
@@ -805,9 +823,9 @@ easy_df_const (op)
/* Return 1 if OP is an EQ or NE comparison operator. */
int
-eqne_comparison_operator (op, mode)
+eqne_comparison_operator (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
enum rtx_code code = GET_CODE (op);
@@ -819,9 +837,9 @@ eqne_comparison_operator (op, mode)
/* Return 1 if OP is a signed comparison operator. */
int
-signed_comparison_operator (op, mode)
+signed_comparison_operator (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
enum rtx_code code = GET_CODE (op);
@@ -835,35 +853,70 @@ signed_comparison_operator (op, mode)
This is used in insn length calcs. */
int
-memreg_operand (op, mode)
+memreg_operand (op, int_mode)
rtx op;
- enum machine_mode mode;
+ int int_mode;
{
return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG;
}
+
+/* Return non-zero if the operand is an insn that is a small insn.
+ Allow const_int 0 as well, which is a placeholder for NOP slots. */
+
+int
+small_insn_p (op, int_mode)
+ rtx op;
+ int int_mode;
+{
+ if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+ return 1;
+
+ if (GET_RTX_CLASS (GET_CODE (op)) != 'i')
+ return 0;
+
+ return get_attr_length (op) == 2;
+}
+
+/* Return non-zero if the operand is an insn that is a large insn. */
+
+int
+large_insn_p (op, int_mode)
+ rtx op;
+ int int_mode;
+{
+ if (GET_RTX_CLASS (GET_CODE (op)) != 'i')
+ return 0;
+
+ return get_attr_length (op) != 2;
+}
+
/* Comparisons. */
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
-enum machine_mode
+int
m32r_select_cc_mode (op, x, y)
- enum rtx_code op;
+ int op;
rtx x, y;
{
- return CCmode;
+ return (int)CCmode;
}
/* X and Y are two things to compare using CODE. Emit the compare insn and
- return the rtx for compare [arg0 of the if_then_else]. */
+ return the rtx for compare [arg0 of the if_then_else].
+ If need_compare is true then the comparison insn must be generated, rather
+ than being susummed into the following branch instruction. */
rtx
-gen_compare (code, x, y)
- enum rtx_code code;
+gen_compare (int_code, x, y, need_compare)
+ int int_code;
rtx x;
rtx y;
+ int need_compare;
{
+ enum rtx_code code = (enum rtx_code)int_code;
enum rtx_code compare_code;
enum rtx_code branch_code;
enum machine_mode mode = SELECT_CC_MODE (code, x, y);
@@ -884,7 +937,122 @@ gen_compare (code, x, y)
case GEU: compare_code = LTU; branch_code = EQ; break;
}
- if (! TARGET_OLD_COMPARE)
+ if (need_compare)
+ {
+ switch (compare_code)
+ {
+ case EQ:
+ if (GET_CODE (y) == CONST_INT
+ && CMP_INT16_P (INTVAL (y)) /* reg equal to small const. */
+ && y != const0_rtx)
+ {
+ rtx tmp = gen_reg_rtx (SImode);
+
+ emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y));
+ x = tmp;
+ y = const0_rtx;
+ }
+ else if (CONSTANT_P (y)) /* reg equal to const. */
+ {
+ rtx tmp = force_reg (GET_MODE (x), y);
+ y = tmp;
+ }
+
+ if (register_operand (y, SImode) /* reg equal to reg. */
+ || y == const0_rtx) /* req equal to zero. */
+ {
+ emit_insn (gen_cmp_eqsi_insn (x, y));
+
+ return gen_rtx (code, mode, cc_reg, const0_rtx);
+ }
+ break;
+
+ case LT:
+ if (register_operand (y, SImode)
+ || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
+ {
+ rtx tmp = gen_reg_rtx (SImode); /* reg compared to reg. */
+
+ switch (code)
+ {
+ case LT:
+ emit_insn (gen_cmp_ltsi_insn (x, y));
+ code = EQ;
+ break;
+ case LE:
+ if (y == const0_rtx)
+ tmp = const1_rtx;
+ else
+ emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+ emit_insn (gen_cmp_ltsi_insn (x, tmp));
+ code = EQ;
+ break;
+ case GT:
+ if (GET_CODE (y) == CONST_INT)
+ tmp = gen_rtx (PLUS, SImode, y, const1_rtx);
+ else
+ emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+ emit_insn (gen_cmp_ltsi_insn (x, tmp));
+ code = NE;
+ break;
+ case GE:
+ emit_insn (gen_cmp_ltsi_insn (x, y));
+ code = NE;
+ break;
+ default:
+ abort();
+ }
+
+ return gen_rtx (code, mode, cc_reg, const0_rtx);
+ }
+ break;
+
+ case LTU:
+ if (register_operand (y, SImode)
+ || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
+ {
+ rtx tmp = gen_reg_rtx (SImode); /* reg (unsigned) compared to reg. */
+
+ switch (code)
+ {
+ case LTU:
+ emit_insn (gen_cmp_ltusi_insn (x, y));
+ code = EQ;
+ break;
+ case LEU:
+ if (y == const0_rtx)
+ tmp = const1_rtx;
+ else
+ emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+ emit_insn (gen_cmp_ltusi_insn (x, tmp));
+ code = EQ;
+ break;
+ case GTU:
+ if (GET_CODE (y) == CONST_INT)
+ tmp = gen_rtx (PLUS, SImode, y, const1_rtx);
+ else
+ emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+ emit_insn (gen_cmp_ltusi_insn (x, tmp));
+ code = NE;
+ break;
+ case GEU:
+ emit_insn (gen_cmp_ltusi_insn (x, y));
+ code = NE;
+ break;
+ default:
+ abort();
+ }
+
+ return gen_rtx (code, mode, cc_reg, const0_rtx);
+ }
+ break;
+
+ default:
+ abort();
+ }
+ }
+ else
+ if (! TARGET_OLD_COMPARE)
{
/* reg/reg equal comparison */
if (compare_code == EQ
@@ -950,12 +1118,13 @@ gen_compare (code, x, y)
/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */
int
-function_arg_partial_nregs (cum, mode, type, named)
+function_arg_partial_nregs (cum, int_mode, type, named)
CUMULATIVE_ARGS *cum;
- enum machine_mode mode;
+ int int_mode;
tree type;
int named;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
int ret;
int size = (((mode == BLKmode && type)
? int_size_in_bytes (type)
@@ -979,13 +1148,14 @@ function_arg_partial_nregs (cum, mode, type, named)
and mode MODE, and we rely on this fact. */
void
-m32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
+m32r_setup_incoming_varargs (cum, int_mode, type, pretend_size, no_rtl)
CUMULATIVE_ARGS *cum;
- enum machine_mode mode;
+ int int_mode;
tree type;
int *pretend_size;
int no_rtl;
{
+ enum machine_mode mode = (enum machine_mode)int_mode;
int first_anon_arg;
if (no_rtl)
@@ -1128,6 +1298,7 @@ struct m32r_frame_info
unsigned int args_size; /* # bytes that outgoing arguments take up */
unsigned int reg_size; /* # bytes needed to store regs */
unsigned int var_size; /* # bytes that variables take up */
+ unsigned int prolog_size; /* # bytes that the prologue takes up */
unsigned int gmask; /* mask of saved gp registers */
unsigned int save_fp; /* nonzero if fp must be saved */
unsigned int save_lr; /* nonzero if lr (return addr) must be saved */
@@ -1153,6 +1324,9 @@ static struct m32r_frame_info zero_frame_info;
#define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])
#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM])
+#define SHORT_INSN_SIZE 2 /* size of small instructions */
+#define LONG_INSN_SIZE 4 /* size of long instructions */
+
/* Return the bytes needed to compute the frame pointer from the current
stack pointer.
@@ -1164,7 +1338,7 @@ m32r_compute_frame_size (size)
{
int regno;
unsigned int total_size, var_size, args_size, pretend_size, extra_size;
- unsigned int reg_size;
+ unsigned int reg_size, prolog_size, frame_size;
unsigned int gmask;
enum m32r_function_type fn_type;
int interrupt_p;
@@ -1175,6 +1349,7 @@ m32r_compute_frame_size (size)
extra_size = FIRST_PARM_OFFSET (0);
total_size = extra_size + pretend_size + args_size + var_size;
reg_size = 0;
+ prolog_size = 0;
gmask = 0;
/* See if this is an interrupt handler. Call used registers must be saved
@@ -1204,6 +1379,33 @@ m32r_compute_frame_size (size)
handler will do the right thing if this changes total_size. */
total_size = M32R_STACK_ALIGN (total_size);
+ /* Calculate prologue size. Obviously any changes to
+ m32r_output_function_prologue must be mirrored here. */
+ if (pretend_size)
+ prolog_size += SHORT_INSN_SIZE; /* addi sp,-pretend_size */
+
+ prolog_size += SHORT_INSN_SIZE * (reg_size / UNITS_PER_WORD); /* pushes */
+ frame_size = total_size - (pretend_size + reg_size);
+
+ if (frame_size == 0)
+ ; /* nothing to do */
+ else if (frame_size <= 128)
+ prolog_size += SHORT_INSN_SIZE; /* addi sp,-<frame> */
+ else
+ {
+ if ((prolog_size % LONG_INSN_SIZE) != 0)
+ prolog_size += SHORT_INSN_SIZE; /* nop */
+
+ if (frame_size <= 32768)
+ prolog_size += LONG_INSN_SIZE; /* add3 sp,sp,-<frame> */
+ else
+ prolog_size += (LONG_INSN_SIZE /* ld24 tmp,<frame>/sub sp,tmp */
+ + SHORT_INSN_SIZE);
+ }
+
+ if (frame_pointer_needed)
+ prolog_size += SHORT_INSN_SIZE; /* mv fp,sp */
+
/* Save computed information. */
current_frame_info.total_size = total_size;
current_frame_info.extra_size = extra_size;
@@ -1211,6 +1413,7 @@ m32r_compute_frame_size (size)
current_frame_info.var_size = var_size;
current_frame_info.args_size = args_size;
current_frame_info.reg_size = reg_size;
+ current_frame_info.prolog_size = prolog_size;
current_frame_info.gmask = gmask;
current_frame_info.initialized = reload_completed;
@@ -1218,7 +1421,22 @@ m32r_compute_frame_size (size)
return total_size;
}
-/* Set up the stack and frame pointer (if desired) for the function. */
+/* When the `length' insn attribute is used, this macro specifies the
+ value to be assigned to the address of the first insn in a
+ function. If not specified, 0 is used. */
+
+int
+m32r_first_insn_address ()
+{
+ if (! current_frame_info.initialized)
+ m32r_compute_frame_size (get_frame_size ());
+
+ return current_frame_info.prolog_size;
+}
+
+/* Set up the stack and frame pointer (if desired) for the function.
+ Note, if this is changed, you need to mirror the changes in
+ m32r_compute_frame_size which calculates the prolog size. */
void
m32r_output_function_prologue (file, size)
@@ -1239,17 +1457,19 @@ m32r_output_function_prologue (file, size)
ASM_COMMENT_START);
}
+ total_size = (! current_frame_info.initialized
+ ? m32r_compute_frame_size (size)
+ : current_frame_info.total_size);
+
/* This is only for the human reader. */
- fprintf (file, "\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n",
- ASM_COMMENT_START, ASM_COMMENT_START,
+ fprintf (file,
+ "\t%s BEGIN PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d, prolog= %d\n",
+ ASM_COMMENT_START,
current_frame_info.var_size,
current_frame_info.reg_size / 4,
current_frame_info.args_size,
- current_frame_info.extra_size);
-
- total_size = (! current_frame_info.initialized
- ? m32r_compute_frame_size (size)
- : current_frame_info.total_size);
+ current_frame_info.extra_size,
+ current_frame_info.prolog_size);
/* These cases shouldn't happen. Catch them now. */
if (total_size == 0 && gmask)
@@ -1767,3 +1987,127 @@ m32r_print_operand_address (file, addr)
break;
}
}
+
+/* Return true if the operands are the constants 0 and 1. */
+int
+zero_and_one (operand1, operand2)
+ rtx operand1;
+ rtx operand2;
+{
+ return
+ GET_CODE (operand1) == CONST_INT
+ && GET_CODE (operand2) == CONST_INT
+ && ( ((INTVAL (operand1) == 0) && (INTVAL (operand2) == 1))
+ ||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0)));
+}
+
+/* Return non-zero if the operand is suitable for use in a conditional move sequence. */
+int
+conditional_move_operand (operand, int_mode)
+ rtx operand;
+ int int_mode;
+{
+ enum machine_mode mode = (enum machine_mode)int_mode;
+
+ /* Only defined for simple integers so far... */
+ if (mode != SImode && mode != HImode && mode != QImode)
+ return FALSE;
+
+ /* At the moment we can hanndle moving registers and loading constants. */
+ /* To be added: Addition/subtraction/bitops/multiplication of registers. */
+
+ switch (GET_CODE (operand))
+ {
+ case REG:
+ return 1;
+
+ case CONST_INT:
+ return INT8_P (INTVAL (operand));
+
+ default:
+#if 0
+ fprintf (stderr, "Test for cond move op of type: %s\n",
+ GET_RTX_NAME (GET_CODE (operand)));
+#endif
+ return 0;
+ }
+}
+
+/* Return true if the code is a test of the carry bit */
+int
+carry_compare_operand (op, int_mode)
+ rtx op;
+ int int_mode;
+{
+ rtx x;
+
+ if (GET_MODE (op) != CCmode && GET_MODE (op) != VOIDmode)
+ return FALSE;
+
+ if (GET_CODE (op) != NE && GET_CODE (op) != EQ)
+ return FALSE;
+
+ x = XEXP (op, 0);
+ if (GET_CODE (x) != REG || REGNO (x) != CARRY_REGNUM)
+ return FALSE;
+
+ x = XEXP (op, 1);
+ if (GET_CODE (x) != CONST_INT || INTVAL (x) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/* Generate the correct assembler code to handle the conditional loading of a
+ value into a register. It is known that the operands satisfy the
+ conditional_move_operand() function above. The destination is operand[0].
+ The condition is operand [1]. The 'true' value is operand [2] and the
+ 'false' value is operand [3]. */
+char *
+emit_cond_move (operands, insn)
+ rtx * operands;
+ rtx insn;
+{
+ static char buffer [100];
+
+ buffer [0] = 0;
+
+ /* Destination must be a register. */
+ if (GET_CODE (operands [0]) != REG)
+ abort();
+ if (! conditional_move_operand (operands [2], SImode))
+ abort();
+ if (! conditional_move_operand (operands [3], SImode))
+ abort();
+
+
+ /* Check to see if the test is reversed. */
+ if (GET_CODE (operands [1]) == NE)
+ {
+ rtx tmp = operands [2];
+ operands [2] = operands [3];
+ operands [3] = tmp;
+ }
+
+ /* Catch a special case where 0 or 1 is being loaded into the destination.
+ Since we already have these values in the C bit we can use a special
+ instruction. */
+ if (zero_and_one (operands [2], operands [3]))
+ {
+ char * dest = reg_names [REGNO (operands [0])];
+
+ sprintf (buffer, "mvfc %s, cbr", dest);
+
+ /* If the true value was '0' then we need to invert the results of the move. */
+ if (INTVAL (operands [2]) == 0)
+ sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1",
+ dest, dest);
+
+ return buffer;
+ }
+
+
+ return buffer;
+}
+
diff --git a/gcc/config/m32r/m32r.h b/gcc/config/m32r/m32r.h
index d438b495488..199f386433e 100644
--- a/gcc/config/m32r/m32r.h
+++ b/gcc/config/m32r/m32r.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, Mitsubishi M32R cpu.
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (m32r)")
+
/* Switch Recognition by gcc.c. Add -G xx support */
#undef SWITCH_TAKES_ARG
@@ -48,17 +49,18 @@ Boston, MA 02111-1307, USA. */
/* __M32R__ is defined by the existing compiler so we use that. */
#define CPP_PREDEFINES "-Acpu(m32r) -Amachine(m32r) -D__M32R__"
-/* Additional flags for the preprocessor. */
-#define CPP_SPEC ""
#define CC1_SPEC "%{G*}"
-#undef ASM_SPEC
+/* Options to pass on to the assembler. */
+#undef ASM_SPEC
+#define ASM_SPEC "%{v}"
+
#if 0 /* not supported yet */
+#undef ASM_SPEC
#define ASM_SPEC "%{v} %{mrelax:-relax}"
-#else
-#define ASM_SPEC "%{v}"
#endif
+
#undef ASM_FINAL_SPEC
@@ -72,9 +74,11 @@ Boston, MA 02111-1307, USA. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC "%{!shared:crt0.o%s crtsysc.o%s} crtinit.o%s"
+
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtfini.o%s"
+
#undef LIB_SPEC
/* Run-time compilation parameters selecting different hardware subsets. */
@@ -105,6 +109,10 @@ extern int target_flags;
#define TARGET_OLD_COMPARE_MASK 8
#define TARGET_OLD_COMPARE (target_flags & TARGET_OLD_COMPARE_MASK)
+/* Target machine to compile for. */
+#define TARGET_M32R 1
+
+
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
@@ -147,6 +155,8 @@ extern int target_flags;
extern char *m32r_model_string;
extern char *m32r_sdata_string;
+
+
#define TARGET_OPTIONS \
{ \
{ "model=", &m32r_model_string }, \
@@ -239,10 +249,10 @@ extern enum m32r_sdata m32r_sdata;
#define M32R_SDATA_DEFAULT "none"
/* Define this macro as a C expression for the initializer of an array of
- string to tell the driver program which options are defaults for this
+ strings to tell the driver program which options are defaults for this
target and thus do not need to be handled specially when using
`MULTILIB_OPTIONS'. */
-#define MULTILIB_DEFAULTS { "mmodel=small" }
+#define MULTILIB_DEFAULTS { "mmodel=small", "m32r" }
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
@@ -253,8 +263,6 @@ extern enum m32r_sdata m32r_sdata;
Don't use this macro to turn on various extra optimizations for
`-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
-extern void m32r_init ();
-
#define OVERRIDE_OPTIONS \
do { \
/* These need to be done at start up. It's convenient to do them here. */ \
@@ -404,7 +412,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */
#define FIRST_PSEUDO_REGISTER 18
-
+
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
@@ -420,6 +428,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
16 - arg pointer
17 - carry flag
+
By default, the extension registers are not available. */
#define FIXED_REGISTERS \
@@ -427,6 +436,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 0, 1, \
1, 0 }
+
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
@@ -439,6 +449,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
+
/* Zero or more C statements that may conditionally modify two variables
`fixed_regs' and `call_used_regs' (both of type `char []') after they
have been initialized from the two preceding macros.
@@ -531,11 +542,12 @@ enum reg_class {
#define REG_CLASS_CONTENTS \
{ {0}, {0x20000}, {0x1ffff}, {0x3ffff} }
+
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
-extern enum reg_class m32r_regno_reg_class[];
+extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
#define REGNO_REG_CLASS(REGNO) \
(m32r_regno_reg_class[REGNO])
@@ -622,7 +634,11 @@ extern enum reg_class m32r_regno_reg_class[];
C. If C is not defined as an extra constraint, the value returned should
be 0 regardless of VALUE. */
/* Q is for symbolic addresses loadable with ld24.
- R is for symbolic addresses when ld24 can't be used. */
+ R is for symbolic addresses when ld24 can't be used.
+ S is for an 8 bit signed integer in the range +128 to -127 */
+
+#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128)
+
#define EXTRA_CONSTRAINT(VALUE, C) \
((C) == 'Q' \
? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
@@ -630,6 +646,8 @@ extern enum reg_class m32r_regno_reg_class[];
: (C) == 'R' \
? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
|| addr32_operand (VALUE, VOIDmode)) \
+ : (C) == 'S' \
+ ? ((GET_CODE (VALUE) == CONST_INT) && INVERTED_SIGNED_8BIT (INTVAL (VALUE))) \
: 0)
/* Stack layout and stack pointer usage. */
@@ -717,6 +735,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
#define CARRY_REGNUM 17
#define M32R_MAX_INT_REGS 16
+
#define GPR_P(REGNO) ((unsigned) (REGNO) < M32R_MAX_INT_REGS)
/* Eliminating the frame and arg pointers. */
@@ -907,7 +926,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
compiler when this occurs, and how many of the words should go in
registers. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
- function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
+ function_arg_partial_nregs (&CUM, (int)MODE, TYPE, NAMED)
/* A C expression that indicates when an argument must be passed by
reference. If nonzero for an argument, a copy of that argument is
@@ -1218,9 +1237,8 @@ do { \
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
-extern enum machine_mode m32r_select_cc_mode ();
#define SELECT_CC_MODE(OP, X, Y) \
-m32r_select_cc_mode (OP, X, Y)
+((enum machine_mode)m32r_select_cc_mode ((int)OP, X, Y))
/* Return non-zero if SELECT_CC_MODE will never return MODE for a
floating point inequality comparison. */
@@ -1313,6 +1331,38 @@ m32r_select_cc_mode (OP, X, Y)
the improvement wasn't significant and in a couple of cases caused a
significant de-optimization. */
/* #define ENABLE_REGMOVE_PASS */
+
+/* A C statement (sans semicolon) to update the integer variable COST based on
+ the relationship between INSN that is dependent on DEP_INSN through the
+ dependence LINK. The default is to make no adjustment to COST. This can be
+ used for example to specify to the scheduler that an output- or
+ anti-dependence does not incur the same cost as a data-dependence. */
+
+/* #define ADJUST_COST(INSN,LINK,DEP_INSN,COST) \
+ (COST) = m32r_adjust_cost (INSN, LINK, DEP_INSN, COST) */
+
+/* A C statement (sans semicolon) to update the integer scheduling
+ priority `INSN_PRIORITY(INSN)'. Reduce the priority to execute
+ the INSN earlier, increase the priority to execute INSN later.
+ Do not define this macro if you do not need to adjust the
+ scheduling priorities of insns. */
+/* #define ADJUST_PRIORITY (INSN) */
+
+/* Macro to determine whether the Haifa scheduler is used. */
+#ifdef HAIFA
+#define HAIFA_P 1
+#else
+#define HAIFA_P 0
+#endif
+
+/* Indicate how many instructions can be issued at the same time. */
+#define ISSUE_RATE 2
+
+/* When the `length' insn attribute is used, this macro specifies the
+ value to be assigned to the address of the first insn in a
+ function. If not specified, 0 is used. */
+#define FIRST_INSN_ADDRESS m32r_first_insn_address ()
+
/* Section selection. */
@@ -1344,7 +1394,7 @@ DTORS_SECTION_FUNCTION \
SDATA_SECTION_FUNCTION \
SBSS_SECTION_FUNCTION
-#define SDATA_SECTION_FUNCTION \
+#define SDATA_SECTION_FUNCTION \
void \
sdata_section () \
{ \
@@ -1355,7 +1405,7 @@ sdata_section () \
} \
} \
-#define SBSS_SECTION_FUNCTION \
+#define SBSS_SECTION_FUNCTION \
void \
sbss_section () \
{ \
@@ -1429,7 +1479,6 @@ extern void m32r_select_section ();
|| MEDIUM_NAME_P (SYMBOL_NAME) \
|| LARGE_NAME_P (SYMBOL_NAME))
-extern void m32r_encode_section_info ();
#define ENCODE_SECTION_INFO(DECL) m32r_encode_section_info (DECL)
/* Decode SYM_NAME and store the real name part in VAR, sans
@@ -1487,7 +1536,6 @@ do { \
/* Control the assembler format that we output. */
/* Output at beginning of assembler file. */
-extern void m32r_asm_file_start ();
#define ASM_FILE_START(FILE) m32r_asm_file_start (FILE)
/* A C string constant describing how to begin a comment in the target
@@ -1582,7 +1630,7 @@ do { \
#undef ASM_OUTPUT_LABELREF
#define ASM_OUTPUT_LABELREF(FILE, NAME) \
do { \
- char *real_name; \
+ char * real_name; \
STRIP_NAME_ENCODING (real_name, (NAME)); \
fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \
} while (0)
@@ -1713,8 +1761,6 @@ do { \
handling the required alignment of the variable. The alignment is
specified as the number of bits. */
-extern void sbss_section ();
-
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
@@ -1833,35 +1879,146 @@ do { \
/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
is a valid machine specific attribute for DECL.
The attributes in ATTRIBUTES have previously been assigned to TYPE. */
-extern int m32r_valid_machine_attribute ();
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
m32r_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
/* A C expression that returns zero if the attributes on TYPE1 and TYPE2 are
incompatible, one if they are compatible, and two if they are
nearly compatible (which causes a warning to be generated). */
-extern int m32r_comp_type_attributes ();
#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
m32r_comp_type_attributes (TYPE1, TYPE2)
/* Give newly defined TYPE some default attributes. */
-extern void m32r_set_default_type_attributes ();
#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
m32r_set_default_type_attributes (TYPE)
/* Define the information needed to generate branch and scc insns. This is
stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */
-extern struct rtx_def *m32r_compare_op0, *m32r_compare_op1;
-
-/* Define the function that build the compare insn for scc and bcc. */
-extern struct rtx_def *gen_compare ();
+extern struct rtx_def * m32r_compare_op0;
+extern struct rtx_def * m32r_compare_op1;
/* M32R function types. */
-enum m32r_function_type {
+enum m32r_function_type
+{
M32R_FUNCTION_UNKNOWN, M32R_FUNCTION_NORMAL, M32R_FUNCTION_INTERRUPT
};
#define M32R_INTERRUPT_P(TYPE) \
((TYPE) == M32R_FUNCTION_INTERRUPT)
-/* Compute the type of a function from its DECL. */
-enum m32r_function_type m32r_compute_function_type ();
+
+/* Define this if you have defined special-purpose predicates in the
+ file `MACHINE.c'. This macro is called within an initializer of an
+ array of structures. The first field in the structure is the name
+ of a predicate and the second field is an array of rtl codes. For
+ each predicate, list all rtl codes that can be in expressions
+ matched by the predicate. The list should have a trailing comma. */
+
+#define PREDICATE_CODES \
+{ "conditional_move_operand", { REG, SUBREG, CONST_INT }}, \
+{ "carry_compare_operand", { EQ, NE }}, \
+{ "eqne_comparison_operator", { EQ, NE }}, \
+{ "signed_comparison_operator", { EQ, NE, LT, LE, GT, GE }}, \
+{ "move_dest_operand", { REG, SUBREG, MEM }}, \
+{ "move_src_operand", { REG, SUBREG, MEM, CONST_INT, \
+ CONST_DOUBLE, LABEL_REF, CONST, \
+ SYMBOL_REF }}, \
+{ "move_double_src_operand", { REG, SUBREG, MEM, CONST_INT, \
+ CONST_DOUBLE }}, \
+{ "two_insn_const_operand", { CONST_INT }}, \
+{ "symbolic_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
+{ "reg_or_int16_operand", { REG, SUBREG, CONST_INT }}, \
+{ "reg_or_uint16_operand", { REG, SUBREG, CONST_INT }}, \
+{ "reg_or_cmp_int16_operand", { REG, SUBREG, CONST_INT }}, \
+{ "reg_or_zero_operand", { REG, SUBREG, CONST_INT }}, \
+{ "cmp_int16_operand", { CONST_INT }}, \
+{ "call_address_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
+{ "small_insn_p", { INSN, CALL_INSN, JUMP_INSN }}, \
+{ "large_insn_p", { INSN, CALL_INSN, JUMP_INSN }},
+
+/* Functions declared in m32r.c */
+#ifndef PROTO
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define PROTO(ARGS) ARGS
+#else
+#define PROTO(ARGS) ()
+#endif
+#endif
+
+#ifdef BUFSIZE /* stdio.h has been included, ok to use FILE * */
+#define STDIO_PROTO(ARGS) PROTO(ARGS)
+#else
+#define STDIO_PROTO(ARGS) ()
+#endif
+
+#ifndef TREE_CODE
+union tree_node;
+#define Tree union tree_node *
+#else
+#define Tree tree
+#endif
+
+#ifndef RTX_CODE
+struct rtx_def;
+#define Rtx struct rtx_def *
+#else
+#define Rtx rtx
+#endif
+
+extern void sbss_section PROTO((void));
+extern void sdata_section PROTO((void));
+extern void m32r_init PROTO((void));
+extern int m32r_valid_machine_decl_attribute PROTO((Tree, Tree, Tree, Tree));
+extern int m32r_comp_type_attributes PROTO((Tree, Tree));
+extern void m32r_select_section PROTO((Tree, int));
+extern void m32r_encode_section_info PROTO((Tree));
+extern void m32r_init_expanders PROTO((void));
+extern int call_address_operand PROTO((Rtx, int));
+extern int call_operand PROTO((Rtx, int));
+extern int symbolic_operand PROTO((Rtx, int));
+extern int small_data_operand PROTO((Rtx, int));
+extern int addr24_operand PROTO((Rtx, int));
+extern int addr32_operand PROTO((Rtx, int));
+extern int call26_operand PROTO((Rtx, int));
+extern int seth_add3_operand PROTO((Rtx, int));
+extern int cmp_int16_operand PROTO((Rtx, int));
+extern int uint16_operand PROTO((Rtx, int));
+extern int reg_or_int16_operand PROTO((Rtx, int));
+extern int reg_or_uint16_operand PROTO((Rtx, int));
+extern int reg_or_cmp_nt16_operand PROTO((Rtx, int));
+extern int two_insn_const_operand PROTO((Rtx, int));
+extern int move_src_operand PROTO((Rtx, int));
+extern int move_double_src_operand PROTO((Rtx, int));
+extern int move_dest_operand PROTO((Rtx, int));
+extern int easy_di_const PROTO((Rtx));
+extern int easy_df_const PROTO((Rtx));
+extern int eqne_comparison_operator PROTO((Rtx, int));
+extern int signed_comparison_operator PROTO((Rtx, int));
+extern int memreg_operand PROTO((Rtx, int));
+extern int small_insn_p PROTO((Rtx, int));
+extern int large_insn_p PROTO((Rtx, int));
+extern int m32r_select_cc_mode PROTO((int, Rtx, Rtx));
+extern Rtx gen_compare PROTO((int, Rtx, Rtx, int));
+extern int function_arg_partial_nregs PROTO((CUMULATIVE_ARGS *,
+ int, Tree, int));
+extern void m32r_setup_incoming_varargs PROTO((CUMULATIVE_ARGS *,
+ int, Tree, int *,
+ int));
+extern int m32r_address_code PROTO((Rtx));
+extern enum m32r_function_type m32r_compute_function_type
+ PROTO((Tree));
+extern unsigned m32r_compute_frame_size PROTO((int));
+extern int m32r_first_insn_address PROTO((void));
+extern void m32r_output_function_prologue STDIO_PROTO((FILE *, int));
+extern void m32r_output_function_epilogue STDIO_PROTO((FILE *, int));
+extern void m32r_finalize_pic PROTO((void));
+extern void m32r_initialize_trampoline PROTO((Rtx, Rtx, Rtx));
+extern void m32r_asm_file_start STDIO_PROTO((FILE *));
+extern void m32r_print_operand STDIO_PROTO((FILE *, Rtx, int));
+extern void m32r_print_operand_address STDIO_PROTO((FILE *, Rtx));
+extern int zero_and_one PROTO((Rtx, Rtx));
+extern int conditional_move_operand PROTO((Rtx, int));
+extern int carry_compare_operand PROTO((Rtx, int));
+extern char *emit_cond_move PROTO((Rtx *, Rtx));
+
+/* Needed by a peephole optimisation. */
+#define PRESERVE_DEATH_INFO_REGNO_P(regno) (regno < FIRST_PSEUDO_REGISTER)
diff --git a/gcc/config/m32r/m32r.md b/gcc/config/m32r/m32r.md
index 314f3ae4981..49f71d6edda 100644
--- a/gcc/config/m32r/m32r.md
+++ b/gcc/config/m32r/m32r.md
@@ -1,5 +1,5 @@
;; Machine description of the Mitsubishi M32R cpu for GNU C compiler
-;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
;; This file is part of GNU CC.
@@ -65,11 +65,135 @@
(define_asm_attributes
[(set_attr "length" "4")
(set_attr "type" "multi")])
+
+
+;; Whether an instruction is 16-bit or 32-bit
+(define_attr "insn_size" "short,long"
+ (if_then_else (eq_attr "length" "2")
+ (const_string "short")
+ (const_string "long")))
+
+(define_attr "m32r" "no,yes"
+ (const (symbol_ref "(TARGET_M32R != 0)")))
+
+
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Function Units
+;; ::
+;; ::::::::::::::::::::
+
+;; On most RISC machines, there are instructions whose results are not
+;; available for a specific number of cycles. Common cases are instructions
+;; that load data from memory. On many machines, a pipeline stall will result
+;; if the data is referenced too soon after the load instruction.
+
+;; In addition, many newer microprocessors have multiple function units,
+;; usually one for integer and one for floating point, and often will incur
+;; pipeline stalls when a result that is needed is not yet ready.
+
+;; The descriptions in this section allow the specification of how much time
+;; must elapse between the execution of an instruction and the time when its
+;; result is used. It also allows specification of when the execution of an
+;; instruction will delay execution of similar instructions due to function
+;; unit conflicts.
+
+;; For the purposes of the specifications in this section, a machine is divided
+;; into "function units", each of which execute a specific class of
+;; instructions in first-in-first-out order. Function units that accept one
+;; instruction each cycle and allow a result to be used in the succeeding
+;; instruction (usually via forwarding) need not be specified. Classic RISC
+;; microprocessors will normally have a single function unit, which we can call
+;; `memory'. The newer "superscalar" processors will often have function units
+;; for floating point operations, usually at least a floating point adder and
+;; multiplier.
+
+;; Each usage of a function units by a class of insns is specified with a
+;; `define_function_unit' expression, which looks like this:
+
+;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY TEST READY-DELAY
+;; ISSUE-DELAY [CONFLICT-LIST])
+
+;; NAME is a string giving the name of the function unit.
+
+;; MULTIPLICITY is an integer specifying the number of identical units in the
+;; processor. If more than one unit is specified, they will be scheduled
+;; independently. Only truly independent units should be counted; a pipelined
+;; unit should be specified as a single unit. (The only common example of a
+;; machine that has multiple function units for a single instruction class that
+;; are truly independent and not pipelined are the two multiply and two
+;; increment units of the CDC 6600.)
+
+;; SIMULTANEITY specifies the maximum number of insns that can be executing in
+;; each instance of the function unit simultaneously or zero if the unit is
+;; pipelined and has no limit.
+
+;; All `define_function_unit' definitions referring to function unit NAME must
+;; have the same name and values for MULTIPLICITY and SIMULTANEITY.
+
+;; TEST is an attribute test that selects the insns we are describing in this
+;; definition. Note that an insn may use more than one function unit and a
+;; function unit may be specified in more than one `define_function_unit'.
+
+;; READY-DELAY is an integer that specifies the number of cycles after which
+;; the result of the instruction can be used without introducing any stalls.
+
+;; ISSUE-DELAY is an integer that specifies the number of cycles after the
+;; instruction matching the TEST expression begins using this unit until a
+;; subsequent instruction can begin. A cost of N indicates an N-1 cycle delay.
+;; A subsequent instruction may also be delayed if an earlier instruction has a
+;; longer READY-DELAY value. This blocking effect is computed using the
+;; SIMULTANEITY, READY-DELAY, ISSUE-DELAY, and CONFLICT-LIST terms. For a
+;; normal non-pipelined function unit, SIMULTANEITY is one, the unit is taken
+;; to block for the READY-DELAY cycles of the executing insn, and smaller
+;; values of ISSUE-DELAY are ignored.
+
+;; CONFLICT-LIST is an optional list giving detailed conflict costs for this
+;; unit. If specified, it is a list of condition test expressions to be
+;; applied to insns chosen to execute in NAME following the particular insn
+;; matching TEST that is already executing in NAME. For each insn in the list,
+;; ISSUE-DELAY specifies the conflict cost; for insns not in the list, the cost
+;; is zero. If not specified, CONFLICT-LIST defaults to all instructions that
+;; use the function unit.
+
+;; Typical uses of this vector are where a floating point function unit can
+;; pipeline either single- or double-precision operations, but not both, or
+;; where a memory unit can pipeline loads, but not stores, etc.
+
+;; As an example, consider a classic RISC machine where the result of a load
+;; instruction is not available for two cycles (a single "delay" instruction is
+;; required) and where only one load instruction can be executed
+;; simultaneously. This would be specified as:
+
+;; (define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)
+
+;; For the case of a floating point function unit that can pipeline
+;; either single or double precision, but not both, the following could be
+;; specified:
+;;
+;; (define_function_unit "fp" 1 0
+;; (eq_attr "type" "sp_fp") 4 4
+;; [(eq_attr "type" "dp_fp")])
+;;
+;; (define_function_unit "fp" 1 0
+;; (eq_attr "type" "dp_fp") 4 4
+;; [(eq_attr "type" "sp_fp")])
+
+;; Note: The scheduler attempts to avoid function unit conflicts and uses all
+;; the specifications in the `define_function_unit' expression. It has
+;; recently come to our attention that these specifications may not allow
+;; modeling of some of the newer "superscalar" processors that have insns using
+;; multiple pipelined units. These insns will cause a potential conflict for
+;; the second unit used during their execution and there is no way of
+;; representing that conflict. We welcome any examples of how function unit
+;; conflicts work in such processors and suggestions for their representation.
+
;; Function units of the M32R
;; Units that take one cycle do not need to be specified.
-;; (define_function_unit {name} {num-units} {n-users} {test}
+;; (define_function_unit {name} {multiplicity} {simulataneity} {test}
;; {ready-delay} {issue-delay} [{conflict-list}])
;; References to loaded registers should wait a cycle.
@@ -94,6 +218,7 @@
(not (eq_attr "length" "2"))
1 0
[(eq_attr "length" "2")])
+
;; Expand prologue as RTL
;; ??? Unfinished.
@@ -915,6 +1040,7 @@
DONE;
}")
+
;; The cmp_xxx_insn patterns set the condition bit to the result of the
;; comparison. There isn't a "compare equal" instruction so cmp_eqsi_insn
;; is quite inefficient. However, it is rarely used.
@@ -924,10 +1050,23 @@
(eq:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_cmp_int16_operand" "r,P")))
(clobber (match_scratch:SI 2 "=&r,&r"))]
- "TARGET_OLD_COMPARE"
- "@
- mv %2,%0\;sub %2,%1\;cmpui %2,#1
- add3 %2,%0,%#%N1\;cmpui %2,#1"
+ ""
+ "*
+{
+ if (which_alternative == 0)
+ {
+ return \"mv %2,%0\;sub %2,%1\;cmpui %2,#1\";
+ }
+ else
+ {
+ if (INTVAL (operands [1]) == 0)
+ return \"cmpui %0, #1\";
+ else if (REGNO (operands [2]) == REGNO (operands [0]))
+ return \"addi %0,%#%N1\;cmpui %2,#1\";
+ else
+ return \"add3 %2,%0,%#%N1\;cmpui %2,#1\";
+ }
+}"
[(set_attr "type" "compare,compare")
(set_attr "length" "8,8")])
@@ -939,17 +1078,23 @@
"@
cmp %0,%1
cmpi %0,%#%1"
- [(set_attr "type" "compare")])
+ [(set_attr "type" "compare,compare")
+ (set_attr "length" "4,6")])
(define_insn "cmp_ltusi_insn"
[(set (reg:CC 17)
(ltu:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_uint16_operand" "r,K")))]
""
- "@
- cmpu %0,%1
- cmpui %0,%#%1"
- [(set_attr "type" "compare")])
+ "*
+{
+ if (which_alternative == 0)
+ return \"cmpu %0,%1\";
+ else
+ return \"cmpui %0,%#%1\";
+}"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,6")])
;; reg == small constant comparisons are best handled by putting the result
;; of the comparison in a tmp reg and then using beqz/bnez.
@@ -957,13 +1102,15 @@
;; it contains 0/non-zero.
(define_insn "cmp_ne_small_const_insn"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (ne:SI (match_operand:SI 1 "register_operand" "r")
- (match_operand:SI 2 "cmp_int16_operand" "P")))]
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ne:SI (match_operand:SI 1 "register_operand" "0,r")
+ (match_operand:SI 2 "cmp_int16_operand" "S,P")))]
""
- "add3 %0,%1,%#%N2"
+ "@
+ addi %0,%#%N2
+ add3 %0,%1,%#%N2"
[(set_attr "type" "compare")
- (set_attr "length" "4")])
+ (set_attr "length" "2,4")])
;; These control RTL generation for conditional jump insns.
@@ -975,7 +1122,7 @@
""
"
{
- operands[1] = gen_compare (EQ, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)EQ, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bne"
@@ -986,7 +1133,7 @@
""
"
{
- operands[1] = gen_compare (NE, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)NE, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bgt"
@@ -997,7 +1144,7 @@
""
"
{
- operands[1] = gen_compare (GT, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)GT, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "ble"
@@ -1008,7 +1155,7 @@
""
"
{
- operands[1] = gen_compare (LE, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)LE, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bge"
@@ -1019,7 +1166,7 @@
""
"
{
- operands[1] = gen_compare (GE, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)GE, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "blt"
@@ -1030,7 +1177,7 @@
""
"
{
- operands[1] = gen_compare (LT, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)LT, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bgtu"
@@ -1041,7 +1188,7 @@
""
"
{
- operands[1] = gen_compare (GTU, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)GTU, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bleu"
@@ -1052,7 +1199,7 @@
""
"
{
- operands[1] = gen_compare (LEU, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)LEU, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bgeu"
@@ -1063,7 +1210,7 @@
""
"
{
- operands[1] = gen_compare (GEU, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)GEU, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
(define_expand "bltu"
@@ -1074,7 +1221,7 @@
""
"
{
- operands[1] = gen_compare (LTU, m32r_compare_op0, m32r_compare_op1);
+ operands[1] = gen_compare ((int)LTU, m32r_compare_op0, m32r_compare_op1, FALSE);
}")
;; Now match both normal and inverted jump.
@@ -1088,10 +1235,11 @@
""
"*
{
- if (GET_CODE (operands[1]) == NE)
- return \"bc %l0\";
- else
- return \"bnc %l0\";
+ static char instruction[40];
+ sprintf (instruction, \"%s%s %%l0\",
+ (GET_CODE (operands[1]) == NE) ? \"bc\" : \"bnc\",
+ (get_attr_length (insn) == 2) ? \".s\" : \"\");
+ return instruction;
}"
[(set_attr "type" "branch")
; We use 400/800 instead of 512,1024 to account for inaccurate insn
@@ -1116,10 +1264,11 @@
""
"*
{
- if (GET_CODE (operands[1]) == EQ)
- return \"bc %l0\";
- else
- return \"bnc %l0\";
+ static char instruction[40];
+ sprintf (instruction, \"%s%s %%l0\",
+ (GET_CODE (operands[1]) == EQ) ? \"bc\" : \"bnc\",
+ (get_attr_length (insn) == 2) ? \".s\" : \"\");
+ return instruction;
}"
[(set_attr "type" "branch")
; We use 400/800 instead of 512,1024 to account for inaccurate insn
@@ -1452,6 +1601,51 @@
"* return \"nop ; flush-icache\";"
[(set_attr "type" "misc")])
+;; Conditional move instructions
+;; Based on those done for the d10v
+
+
+(define_expand "movsicc"
+ [
+ (set (match_operand:SI 0 "register_operand" "r")
+ (if_then_else:SI (match_operand 1 "" "")
+ (match_operand:SI 2 "conditional_move_operand" "O")
+ (match_operand:SI 3 "conditional_move_operand" "O")
+ )
+ )
+ ]
+ ""
+ "
+{
+ if (! zero_and_one (operands [2], operands [3]))
+ FAIL;
+
+ /* Generate the comparision that will set the carry flag. */
+ operands[1] = gen_compare ((int)GET_CODE (operands[1]), m32r_compare_op0,
+ m32r_compare_op1, TRUE);
+
+ /* See other movsicc pattern below for reason why. */
+ emit_insn (gen_blockage());
+}")
+
+;; Generate the conditional instructions based on how the carry flag is examined.
+(define_insn "*movsicc_internal"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (if_then_else:SI (match_operand 1 "carry_compare_operand" "")
+ (match_operand:SI 2 "conditional_move_operand" "O")
+ (match_operand:SI 3 "conditional_move_operand" "O")
+ )
+ )]
+ "zero_and_one (operands [2], operands[3])"
+ "* return emit_cond_move (operands, insn);"
+ [(set_attr "type" "move")
+ (set_attr "length" "8")
+ ]
+)
+
+
+
+
;; Split up troublesome insns for better scheduling.
;; Peepholes go at the end.
@@ -1467,3 +1661,46 @@
"st %1,@+%0"
[(set_attr "type" "store")
(set_attr "length" "2")])
+
+;; This case is triggered by compiling this code:
+;;
+;; extern void sub(int *);
+;; void main (void)
+;; {
+;; int i=2,j=3,k;
+;; while (i < j) sub(&k);
+;; i = j / k;
+;; sub(&i);
+;; i = j - k;
+;; sub(&i);
+;; }
+;;
+;; Without the peephole the following assembler is generated for the
+;; divide and subtract expressions:
+;;
+;; div r5,r4
+;; mv r4,r5
+;; st r4,@(4,sp)
+;; bl sub
+;;
+;; Simialr code is produced for the subtract expression. With this
+;; peephole the redundant move is eliminated.
+;;
+;; This optimisation onbly works if PRESERVE_DEATH_INFO_REGNO_P is
+;; defined in m32r.h
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "register_operand" "r")
+ )
+ (set (mem:SI (plus: SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "immediate_operand" "J")))
+ (match_dup 0)
+ )
+ ]
+ "dead_or_set_p (insn, operands [0])"
+ "st %1,@(%3,%2)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")
+ ]
+)
diff --git a/gcc/config/m32r/t-m32r b/gcc/config/m32r/t-m32r
index 6005eb96db3..3d8da58c116 100644
--- a/gcc/config/m32r/t-m32r
+++ b/gcc/config/m32r/t-m32r
@@ -39,6 +39,7 @@ crtfini.o: $(srcdir)/config/m32r/initfini.c $(GCC_PASSES) $(CONFIG_H)
-DCRT_FINI -finhibit-size-directive -fno-inline-functions \
-g0 -c $(srcdir)/config/m32r/initfini.c -o crtfini.o
+
# -mmodel={small,medium} requires separate libraries.
# We don't build libraries for the large model, instead we use the medium
# libraries. The only difference is that the large model can handle jumps
@@ -48,6 +49,7 @@ MULTILIB_OPTIONS = mmodel=small/mmodel=medium
MULTILIB_DIRNAMES = small medium
MULTILIB_MATCHES = mmodel?medium=mmodel?large
+
# Set MULTILIB_EXTRA_OPTS so shipped libraries have small data in .sdata and
# SHN_M32R_SCOMMON.
# This is important for objects referenced in system header files.
diff --git a/gcc/configure b/gcc/configure
index 3f2f16c1198..7a4c917b0fb 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -4580,7 +4580,7 @@ fi
if [ x$enable_haifa = x ]
then
case $target in
- alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*)
+ alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-* | m32r*-*)
enable_haifa=yes;;
esac
fi
diff --git a/gcc/configure.in b/gcc/configure.in
index 6e6e34a3fab..67b7fbd7f14 100644
--- a/gcc/configure.in
+++ b/gcc/configure.in
@@ -2891,7 +2891,7 @@ fi
if [[ x$enable_haifa = x ]]
then
case $target in
- alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*)
+ alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-* | m32r*-*)
enable_haifa=yes;;
esac
fi
OpenPOWER on IntegriCloud