update m32r port
From-SVN: r19465
This commit is contained in:
parent
77be0cab5f
commit
2b7972b093
@ -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).
|
||||
|
@ -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,18 +1457,20 @@ m32r_output_function_prologue (file, size)
|
||||
ASM_COMMENT_START);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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);
|
||||
|
||||
/* This is only for the human reader. */
|
||||
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,
|
||||
current_frame_info.prolog_size);
|
||||
|
||||
/* These cases shouldn't happen. Catch them now. */
|
||||
if (total_size == 0 && gmask)
|
||||
abort ();
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,18 +49,19 @@ 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
|
||||
#if 0 /* not supported yet */
|
||||
#define ASM_SPEC "%{v} %{mrelax:-relax}"
|
||||
#else
|
||||
/* 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}"
|
||||
#endif
|
||||
|
||||
|
||||
#undef ASM_FINAL_SPEC
|
||||
|
||||
#undef LINK_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. */ \
|
||||
@ -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)
|
||||
|
@ -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
|
||||
@ -1451,6 +1600,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.
|
||||
|
||||
@ -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")
|
||||
]
|
||||
)
|
||||
|
@ -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.
|
||||
|
2
gcc/configure
vendored
2
gcc/configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user