Commit 2b7972b0 by Michael Meissner Committed by Michael Meissner

update m32r port

From-SVN: r19465
parent 77be0cab
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> Tue Apr 28 07:25:53 1998 Manfred Hollstein <manfred@s-direktnet.de>
* Makefile.in (libgcc2.ready): Revert last patch (Apr 24). * Makefile.in (libgcc2.ready): Revert last patch (Apr 24).
......
/* Subroutines used for code generation on the Mitsubishi M32R cpu. /* 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. This file is part of GNU CC.
...@@ -41,8 +41,6 @@ rtx m32r_compare_op0, m32r_compare_op1; ...@@ -41,8 +41,6 @@ rtx m32r_compare_op0, m32r_compare_op1;
/* Array of valid operand punctuation characters. */ /* Array of valid operand punctuation characters. */
char m32r_punct_chars[256]; char m32r_punct_chars[256];
static void init_reg_tables ();
/* Selected code model. */ /* Selected code model. */
char *m32r_model_string = M32R_MODEL_DEFAULT; char *m32r_model_string = M32R_MODEL_DEFAULT;
enum m32r_model m32r_model; enum m32r_model m32r_model;
...@@ -51,6 +49,10 @@ enum m32r_model m32r_model; ...@@ -51,6 +49,10 @@ enum m32r_model m32r_model;
char *m32r_sdata_string = M32R_SDATA_DEFAULT; char *m32r_sdata_string = M32R_SDATA_DEFAULT;
enum m32r_sdata m32r_sdata; enum m32r_sdata m32r_sdata;
/* Forward declaration. */
static void init_reg_tables PROTO((void));
/* Called by OVERRIDE_OPTIONS to initialize various things. */ /* Called by OVERRIDE_OPTIONS to initialize various things. */
void void
...@@ -84,6 +86,7 @@ m32r_init () ...@@ -84,6 +86,7 @@ m32r_init ()
m32r_sdata = M32R_SDATA_USE; m32r_sdata = M32R_SDATA_USE;
else else
error ("bad value (%s) for -msdata switch", m32r_sdata_string); error ("bad value (%s) for -msdata switch", m32r_sdata_string);
} }
/* Vectors to keep interesting information about registers where it can easily /* Vectors to keep interesting information about registers where it can easily
...@@ -95,7 +98,8 @@ m32r_init () ...@@ -95,7 +98,8 @@ m32r_init ()
they all fit (as bit numbers) in a 32 bit word (again). Each real mode is they all fit (as bit numbers) in a 32 bit word (again). Each real mode is
mapped into one m32r_mode_class mode. */ mapped into one m32r_mode_class mode. */
enum m32r_mode_class { enum m32r_mode_class
{
C_MODE, C_MODE,
S_MODE, D_MODE, T_MODE, O_MODE, S_MODE, D_MODE, T_MODE, O_MODE,
SF_MODE, DF_MODE, TF_MODE, OF_MODE SF_MODE, DF_MODE, TF_MODE, OF_MODE
...@@ -113,9 +117,11 @@ enum m32r_mode_class { ...@@ -113,9 +117,11 @@ enum m32r_mode_class {
/* Modes for quad-word and smaller quantities. */ /* Modes for quad-word and smaller quantities. */
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE)) #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
/* Value is 1 if register/mode pair is acceptable on arc. */ /* 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, T_MODES, T_MODES, T_MODES,
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES,
S_MODES, C_MODES S_MODES, C_MODES
...@@ -412,21 +418,23 @@ m32r_init_expanders () ...@@ -412,21 +418,23 @@ m32r_init_expanders ()
/* Acceptable arguments to the call insn. */ /* Acceptable arguments to the call insn. */
int int
call_address_operand (op, mode) call_address_operand (op, int_mode)
rtx op; 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 /* Constants and values in registers are not OK, because
the m32r BL instruction can only support PC relative branching. */ the m32r BL instruction can only support PC relative branching. */
} }
int int
call_operand (op, mode) call_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
enum machine_mode mode = (enum machine_mode)int_mode;
if (GET_CODE (op) != MEM) if (GET_CODE (op) != MEM)
return 0; return 0;
op = XEXP (op, 0); op = XEXP (op, 0);
...@@ -436,9 +444,9 @@ call_operand (op, mode) ...@@ -436,9 +444,9 @@ call_operand (op, mode)
/* Returns 1 if OP is a symbol reference. */ /* Returns 1 if OP is a symbol reference. */
int int
symbolic_operand (op, mode) symbolic_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
switch (GET_CODE (op)) switch (GET_CODE (op))
{ {
...@@ -446,6 +454,7 @@ symbolic_operand (op, mode) ...@@ -446,6 +454,7 @@ symbolic_operand (op, mode)
case LABEL_REF: case LABEL_REF:
case CONST : case CONST :
return 1; return 1;
default: default:
return 0; return 0;
} }
...@@ -454,9 +463,9 @@ symbolic_operand (op, mode) ...@@ -454,9 +463,9 @@ symbolic_operand (op, mode)
/* Return 1 if OP is a reference to an object in .sdata/.sbss. */ /* Return 1 if OP is a reference to an object in .sdata/.sbss. */
int int
small_data_operand (op, mode) small_data_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (! TARGET_SDATA_USE) if (! TARGET_SDATA_USE)
return 0; return 0;
...@@ -477,9 +486,9 @@ small_data_operand (op, mode) ...@@ -477,9 +486,9 @@ small_data_operand (op, mode)
/* Return 1 if OP is a symbol that can use 24 bit addressing. */ /* Return 1 if OP is a symbol that can use 24 bit addressing. */
int int
addr24_operand (op, mode) addr24_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) == LABEL_REF) if (GET_CODE (op) == LABEL_REF)
return TARGET_ADDR24; return TARGET_ADDR24;
...@@ -509,24 +518,24 @@ addr24_operand (op, mode) ...@@ -509,24 +518,24 @@ addr24_operand (op, mode)
/* Return 1 if OP is a symbol that needs 32 bit addressing. */ /* Return 1 if OP is a symbol that needs 32 bit addressing. */
int int
addr32_operand (op, mode) addr32_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) == LABEL_REF) if (GET_CODE (op) == LABEL_REF)
return TARGET_ADDR32; return TARGET_ADDR32;
if (GET_CODE (op) == SYMBOL_REF) if (GET_CODE (op) == SYMBOL_REF)
return (! addr24_operand (op) return (! addr24_operand (op, int_mode)
&& ! small_data_operand (op)); && ! small_data_operand (op, int_mode));
if (GET_CODE (op) == CONST if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS && GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
{ {
return (! addr24_operand (op) return (! addr24_operand (op, int_mode)
&& ! small_data_operand (op)); && ! small_data_operand (op, int_mode));
} }
return 0; return 0;
...@@ -535,9 +544,9 @@ addr32_operand (op, mode) ...@@ -535,9 +544,9 @@ addr32_operand (op, mode)
/* Return 1 if OP is a function that can be called with the `bl' insn. */ /* Return 1 if OP is a function that can be called with the `bl' insn. */
int int
call26_operand (op, mode) call26_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) == SYMBOL_REF) if (GET_CODE (op) == SYMBOL_REF)
return ! LARGE_NAME_P (XSTR (op, 0)); return ! LARGE_NAME_P (XSTR (op, 0));
...@@ -548,9 +557,9 @@ call26_operand (op, mode) ...@@ -548,9 +557,9 @@ call26_operand (op, mode)
/* Returns 1 if OP is an acceptable operand for seth/add3. */ /* Returns 1 if OP is an acceptable operand for seth/add3. */
int int
seth_add3_operand (op, mode) seth_add3_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) == SYMBOL_REF if (GET_CODE (op) == SYMBOL_REF
|| GET_CODE (op) == LABEL_REF) || GET_CODE (op) == LABEL_REF)
...@@ -570,9 +579,9 @@ seth_add3_operand (op, mode) ...@@ -570,9 +579,9 @@ seth_add3_operand (op, mode)
useful in comparisons. */ useful in comparisons. */
int int
cmp_int16_operand (op, mode) cmp_int16_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) != CONST_INT) if (GET_CODE (op) != CONST_INT)
return 0; return 0;
...@@ -581,10 +590,10 @@ cmp_int16_operand (op, mode) ...@@ -581,10 +590,10 @@ cmp_int16_operand (op, mode)
/* Return true if OP is an unsigned 16 bit immediate value. */ /* Return true if OP is an unsigned 16 bit immediate value. */
static int int
uint16_operand (op, mode) uint16_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) != CONST_INT) if (GET_CODE (op) != CONST_INT)
return 0; return 0;
...@@ -594,10 +603,12 @@ uint16_operand (op, mode) ...@@ -594,10 +603,12 @@ uint16_operand (op, mode)
/* Return true if OP is a register or signed 8 bit value. */ /* Return true if OP is a register or signed 8 bit value. */
int int
reg_or_int16_operand (op, mode) reg_or_int16_operand (op, int_mode)
rtx op; 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) if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode); return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT) if (GET_CODE (op) != CONST_INT)
...@@ -608,10 +619,12 @@ reg_or_int16_operand (op, mode) ...@@ -608,10 +619,12 @@ reg_or_int16_operand (op, mode)
/* Return true if OP is a register or an unsigned 16 bit value. */ /* Return true if OP is a register or an unsigned 16 bit value. */
int int
reg_or_uint16_operand (op, mode) reg_or_uint16_operand (op, int_mode)
rtx op; 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) if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode); return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT) if (GET_CODE (op) != CONST_INT)
...@@ -622,10 +635,12 @@ reg_or_uint16_operand (op, mode) ...@@ -622,10 +635,12 @@ reg_or_uint16_operand (op, mode)
/* Return true if OP is a register or signed 16 bit value for compares. */ /* Return true if OP is a register or signed 16 bit value for compares. */
int int
reg_or_cmp_int16_operand (op, mode) reg_or_cmp_int16_operand (op, int_mode)
rtx op; 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) if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode); return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT) if (GET_CODE (op) != CONST_INT)
...@@ -636,9 +651,9 @@ reg_or_cmp_int16_operand (op, mode) ...@@ -636,9 +651,9 @@ reg_or_cmp_int16_operand (op, mode)
/* Return true if OP is a const_int requiring two instructions to load. */ /* Return true if OP is a const_int requiring two instructions to load. */
int int
two_insn_const_operand (op, mode) two_insn_const_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
if (GET_CODE (op) != CONST_INT) if (GET_CODE (op) != CONST_INT)
return 0; return 0;
...@@ -653,15 +668,16 @@ two_insn_const_operand (op, mode) ...@@ -653,15 +668,16 @@ two_insn_const_operand (op, mode)
move source. */ move source. */
int int
move_src_operand (op, mode) move_src_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op)) switch (GET_CODE (op))
{ {
case SYMBOL_REF : case SYMBOL_REF :
case CONST : case CONST :
return addr24_operand (op, mode); return addr24_operand (op, int_mode);
case CONST_INT : case CONST_INT :
/* ??? We allow more cse opportunities if we only allow constants /* ??? We allow more cse opportunities if we only allow constants
loadable with one insn, and split the rest into two. The instances loadable with one insn, and split the rest into two. The instances
...@@ -704,10 +720,11 @@ move_src_operand (op, mode) ...@@ -704,10 +720,11 @@ move_src_operand (op, mode)
move source. */ move source. */
int int
move_double_src_operand (op, mode) move_double_src_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op)) switch (GET_CODE (op))
{ {
case CONST_INT : case CONST_INT :
...@@ -722,7 +739,7 @@ move_double_src_operand (op, mode) ...@@ -722,7 +739,7 @@ move_double_src_operand (op, mode)
/* (subreg (mem ...) ...) can occur here if the inner part was once a /* (subreg (mem ...) ...) can occur here if the inner part was once a
pseudo-reg and is now a stack slot. */ pseudo-reg and is now a stack slot. */
if (GET_CODE (SUBREG_REG (op)) == MEM) 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 else
return register_operand (op, mode); return register_operand (op, mode);
case MEM : case MEM :
...@@ -739,10 +756,11 @@ move_double_src_operand (op, mode) ...@@ -739,10 +756,11 @@ move_double_src_operand (op, mode)
/* Return true if OP is an acceptable argument for a move destination. */ /* Return true if OP is an acceptable argument for a move destination. */
int int
move_dest_operand (op, mode) move_dest_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op)) switch (GET_CODE (op))
{ {
case REG : case REG :
...@@ -805,9 +823,9 @@ easy_df_const (op) ...@@ -805,9 +823,9 @@ easy_df_const (op)
/* Return 1 if OP is an EQ or NE comparison operator. */ /* Return 1 if OP is an EQ or NE comparison operator. */
int int
eqne_comparison_operator (op, mode) eqne_comparison_operator (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
enum rtx_code code = GET_CODE (op); enum rtx_code code = GET_CODE (op);
...@@ -819,9 +837,9 @@ eqne_comparison_operator (op, mode) ...@@ -819,9 +837,9 @@ eqne_comparison_operator (op, mode)
/* Return 1 if OP is a signed comparison operator. */ /* Return 1 if OP is a signed comparison operator. */
int int
signed_comparison_operator (op, mode) signed_comparison_operator (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
enum rtx_code code = GET_CODE (op); enum rtx_code code = GET_CODE (op);
...@@ -835,35 +853,70 @@ signed_comparison_operator (op, mode) ...@@ -835,35 +853,70 @@ signed_comparison_operator (op, mode)
This is used in insn length calcs. */ This is used in insn length calcs. */
int int
memreg_operand (op, mode) memreg_operand (op, int_mode)
rtx op; rtx op;
enum machine_mode mode; int int_mode;
{ {
return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG; 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. */ /* Comparisons. */
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */ return the mode to be used for the comparison. */
enum machine_mode int
m32r_select_cc_mode (op, x, y) m32r_select_cc_mode (op, x, y)
enum rtx_code op; int op;
rtx x, y; rtx x, y;
{ {
return CCmode; return (int)CCmode;
} }
/* X and Y are two things to compare using CODE. Emit the compare insn and /* 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 rtx
gen_compare (code, x, y) gen_compare (int_code, x, y, need_compare)
enum rtx_code code; int int_code;
rtx x; rtx x;
rtx y; rtx y;
int need_compare;
{ {
enum rtx_code code = (enum rtx_code)int_code;
enum rtx_code compare_code; enum rtx_code compare_code;
enum rtx_code branch_code; enum rtx_code branch_code;
enum machine_mode mode = SELECT_CC_MODE (code, x, y); enum machine_mode mode = SELECT_CC_MODE (code, x, y);
...@@ -884,7 +937,122 @@ gen_compare (code, x, y) ...@@ -884,7 +937,122 @@ gen_compare (code, x, y)
case GEU: compare_code = LTU; branch_code = EQ; break; 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 */ /* reg/reg equal comparison */
if (compare_code == EQ if (compare_code == EQ
...@@ -950,12 +1118,13 @@ gen_compare (code, x, y) ...@@ -950,12 +1118,13 @@ gen_compare (code, x, y)
/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */ /* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */
int int
function_arg_partial_nregs (cum, mode, type, named) function_arg_partial_nregs (cum, int_mode, type, named)
CUMULATIVE_ARGS *cum; CUMULATIVE_ARGS *cum;
enum machine_mode mode; int int_mode;
tree type; tree type;
int named; int named;
{ {
enum machine_mode mode = (enum machine_mode)int_mode;
int ret; int ret;
int size = (((mode == BLKmode && type) int size = (((mode == BLKmode && type)
? int_size_in_bytes (type) ? int_size_in_bytes (type)
...@@ -979,13 +1148,14 @@ function_arg_partial_nregs (cum, mode, type, named) ...@@ -979,13 +1148,14 @@ function_arg_partial_nregs (cum, mode, type, named)
and mode MODE, and we rely on this fact. */ and mode MODE, and we rely on this fact. */
void 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; CUMULATIVE_ARGS *cum;
enum machine_mode mode; int int_mode;
tree type; tree type;
int *pretend_size; int *pretend_size;
int no_rtl; int no_rtl;
{ {
enum machine_mode mode = (enum machine_mode)int_mode;
int first_anon_arg; int first_anon_arg;
if (no_rtl) if (no_rtl)
...@@ -1128,6 +1298,7 @@ struct m32r_frame_info ...@@ -1128,6 +1298,7 @@ struct m32r_frame_info
unsigned int args_size; /* # bytes that outgoing arguments take up */ unsigned int args_size; /* # bytes that outgoing arguments take up */
unsigned int reg_size; /* # bytes needed to store regs */ unsigned int reg_size; /* # bytes needed to store regs */
unsigned int var_size; /* # bytes that variables take up */ 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 gmask; /* mask of saved gp registers */
unsigned int save_fp; /* nonzero if fp must be saved */ unsigned int save_fp; /* nonzero if fp must be saved */
unsigned int save_lr; /* nonzero if lr (return addr) 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; ...@@ -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_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])
#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_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 /* Return the bytes needed to compute the frame pointer from the current
stack pointer. stack pointer.
...@@ -1164,7 +1338,7 @@ m32r_compute_frame_size (size) ...@@ -1164,7 +1338,7 @@ m32r_compute_frame_size (size)
{ {
int regno; int regno;
unsigned int total_size, var_size, args_size, pretend_size, extra_size; 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; unsigned int gmask;
enum m32r_function_type fn_type; enum m32r_function_type fn_type;
int interrupt_p; int interrupt_p;
...@@ -1175,6 +1349,7 @@ m32r_compute_frame_size (size) ...@@ -1175,6 +1349,7 @@ m32r_compute_frame_size (size)
extra_size = FIRST_PARM_OFFSET (0); extra_size = FIRST_PARM_OFFSET (0);
total_size = extra_size + pretend_size + args_size + var_size; total_size = extra_size + pretend_size + args_size + var_size;
reg_size = 0; reg_size = 0;
prolog_size = 0;
gmask = 0; gmask = 0;
/* See if this is an interrupt handler. Call used registers must be saved /* See if this is an interrupt handler. Call used registers must be saved
...@@ -1204,6 +1379,33 @@ m32r_compute_frame_size (size) ...@@ -1204,6 +1379,33 @@ m32r_compute_frame_size (size)
handler will do the right thing if this changes total_size. */ handler will do the right thing if this changes total_size. */
total_size = M32R_STACK_ALIGN (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. */ /* Save computed information. */
current_frame_info.total_size = total_size; current_frame_info.total_size = total_size;
current_frame_info.extra_size = extra_size; current_frame_info.extra_size = extra_size;
...@@ -1211,6 +1413,7 @@ m32r_compute_frame_size (size) ...@@ -1211,6 +1413,7 @@ m32r_compute_frame_size (size)
current_frame_info.var_size = var_size; current_frame_info.var_size = var_size;
current_frame_info.args_size = args_size; current_frame_info.args_size = args_size;
current_frame_info.reg_size = reg_size; current_frame_info.reg_size = reg_size;
current_frame_info.prolog_size = prolog_size;
current_frame_info.gmask = gmask; current_frame_info.gmask = gmask;
current_frame_info.initialized = reload_completed; current_frame_info.initialized = reload_completed;
...@@ -1218,7 +1421,22 @@ m32r_compute_frame_size (size) ...@@ -1218,7 +1421,22 @@ m32r_compute_frame_size (size)
return total_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 void
m32r_output_function_prologue (file, size) m32r_output_function_prologue (file, size)
...@@ -1239,17 +1457,19 @@ m32r_output_function_prologue (file, size) ...@@ -1239,17 +1457,19 @@ m32r_output_function_prologue (file, size)
ASM_COMMENT_START); 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. */ /* This is only for the human reader. */
fprintf (file, "\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n", fprintf (file,
ASM_COMMENT_START, ASM_COMMENT_START, "\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.var_size,
current_frame_info.reg_size / 4, current_frame_info.reg_size / 4,
current_frame_info.args_size, current_frame_info.args_size,
current_frame_info.extra_size); current_frame_info.extra_size,
current_frame_info.prolog_size);
total_size = (! current_frame_info.initialized
? m32r_compute_frame_size (size)
: current_frame_info.total_size);
/* These cases shouldn't happen. Catch them now. */ /* These cases shouldn't happen. Catch them now. */
if (total_size == 0 && gmask) if (total_size == 0 && gmask)
...@@ -1767,3 +1987,127 @@ m32r_print_operand_address (file, addr) ...@@ -1767,3 +1987,127 @@ m32r_print_operand_address (file, addr)
break; 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;
}
/* Definitions of target machine for GNU compiler, Mitsubishi M32R cpu. /* 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. This file is part of GNU CC.
...@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */ ...@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */
/* Print subsidiary information on the compiler version in use. */ /* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (m32r)") #define TARGET_VERSION fprintf (stderr, " (m32r)")
/* Switch Recognition by gcc.c. Add -G xx support */ /* Switch Recognition by gcc.c. Add -G xx support */
#undef SWITCH_TAKES_ARG #undef SWITCH_TAKES_ARG
...@@ -48,17 +49,18 @@ Boston, MA 02111-1307, USA. */ ...@@ -48,17 +49,18 @@ Boston, MA 02111-1307, USA. */
/* __M32R__ is defined by the existing compiler so we use that. */ /* __M32R__ is defined by the existing compiler so we use that. */
#define CPP_PREDEFINES "-Acpu(m32r) -Amachine(m32r) -D__M32R__" #define CPP_PREDEFINES "-Acpu(m32r) -Amachine(m32r) -D__M32R__"
/* Additional flags for the preprocessor. */
#define CPP_SPEC ""
#define CC1_SPEC "%{G*}" #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 */ #if 0 /* not supported yet */
#undef ASM_SPEC
#define ASM_SPEC "%{v} %{mrelax:-relax}" #define ASM_SPEC "%{v} %{mrelax:-relax}"
#else
#define ASM_SPEC "%{v}"
#endif #endif
#undef ASM_FINAL_SPEC #undef ASM_FINAL_SPEC
...@@ -72,9 +74,11 @@ Boston, MA 02111-1307, USA. */ ...@@ -72,9 +74,11 @@ Boston, MA 02111-1307, USA. */
#undef STARTFILE_SPEC #undef STARTFILE_SPEC
#define STARTFILE_SPEC "%{!shared:crt0.o%s crtsysc.o%s} crtinit.o%s" #define STARTFILE_SPEC "%{!shared:crt0.o%s crtsysc.o%s} crtinit.o%s"
#undef ENDFILE_SPEC #undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtfini.o%s" #define ENDFILE_SPEC "crtfini.o%s"
#undef LIB_SPEC #undef LIB_SPEC
/* Run-time compilation parameters selecting different hardware subsets. */ /* Run-time compilation parameters selecting different hardware subsets. */
...@@ -105,6 +109,10 @@ extern int target_flags; ...@@ -105,6 +109,10 @@ extern int target_flags;
#define TARGET_OLD_COMPARE_MASK 8 #define TARGET_OLD_COMPARE_MASK 8
#define TARGET_OLD_COMPARE (target_flags & TARGET_OLD_COMPARE_MASK) #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. /* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces, This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE } each pair being { "NAME", VALUE }
...@@ -147,6 +155,8 @@ extern int target_flags; ...@@ -147,6 +155,8 @@ extern int target_flags;
extern char *m32r_model_string; extern char *m32r_model_string;
extern char *m32r_sdata_string; extern char *m32r_sdata_string;
#define TARGET_OPTIONS \ #define TARGET_OPTIONS \
{ \ { \
{ "model=", &m32r_model_string }, \ { "model=", &m32r_model_string }, \
...@@ -239,10 +249,10 @@ extern enum m32r_sdata m32r_sdata; ...@@ -239,10 +249,10 @@ extern enum m32r_sdata m32r_sdata;
#define M32R_SDATA_DEFAULT "none" #define M32R_SDATA_DEFAULT "none"
/* Define this macro as a C expression for the initializer of an array of /* 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 target and thus do not need to be handled specially when using
`MULTILIB_OPTIONS'. */ `MULTILIB_OPTIONS'. */
#define MULTILIB_DEFAULTS { "mmodel=small" } #define MULTILIB_DEFAULTS { "mmodel=small", "m32r" }
/* Sometimes certain combinations of command options do not make /* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro sense on a particular target machine. You can define a macro
...@@ -253,8 +263,6 @@ extern enum m32r_sdata m32r_sdata; ...@@ -253,8 +263,6 @@ extern enum m32r_sdata m32r_sdata;
Don't use this macro to turn on various extra optimizations for Don't use this macro to turn on various extra optimizations for
`-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
extern void m32r_init ();
#define OVERRIDE_OPTIONS \ #define OVERRIDE_OPTIONS \
do { \ do { \
/* These need to be done at start up. It's convenient to do them here. */ \ /* 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 \ ...@@ -404,7 +412,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
All registers that the compiler knows about must be given numbers, All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */ even those that are not normally considered general registers. */
#define FIRST_PSEUDO_REGISTER 18 #define FIRST_PSEUDO_REGISTER 18
/* 1 for registers that have pervasive standard uses /* 1 for registers that have pervasive standard uses
and are not available for the register allocator. and are not available for the register allocator.
...@@ -420,6 +428,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \ ...@@ -420,6 +428,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
16 - arg pointer 16 - arg pointer
17 - carry flag 17 - carry flag
By default, the extension registers are not available. */ By default, the extension registers are not available. */
#define FIXED_REGISTERS \ #define FIXED_REGISTERS \
...@@ -427,6 +436,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \ ...@@ -427,6 +436,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 0, 1, \ 0, 0, 0, 0, 0, 0, 0, 1, \
1, 0 } 1, 0 }
/* 1 for registers not available across function calls. /* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any These must include the FIXED_REGISTERS and also any
registers that can be used without being saved. registers that can be used without being saved.
...@@ -439,6 +449,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \ ...@@ -439,6 +449,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 1, 1, \ 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 } 1, 1 }
/* Zero or more C statements that may conditionally modify two variables /* Zero or more C statements that may conditionally modify two variables
`fixed_regs' and `call_used_regs' (both of type `char []') after they `fixed_regs' and `call_used_regs' (both of type `char []') after they
have been initialized from the two preceding macros. have been initialized from the two preceding macros.
...@@ -531,11 +542,12 @@ enum reg_class { ...@@ -531,11 +542,12 @@ enum reg_class {
#define REG_CLASS_CONTENTS \ #define REG_CLASS_CONTENTS \
{ {0}, {0x20000}, {0x1ffff}, {0x3ffff} } { {0}, {0x20000}, {0x1ffff}, {0x3ffff} }
/* The same information, inverted: /* The same information, inverted:
Return the class number of the smallest class containing Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression reg number REGNO. This could be a conditional expression
or could index an array. */ 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) \ #define REGNO_REG_CLASS(REGNO) \
(m32r_regno_reg_class[REGNO]) (m32r_regno_reg_class[REGNO])
...@@ -622,7 +634,11 @@ extern enum reg_class m32r_regno_reg_class[]; ...@@ -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 C. If C is not defined as an extra constraint, the value returned should
be 0 regardless of VALUE. */ be 0 regardless of VALUE. */
/* Q is for symbolic addresses loadable with ld24. /* 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) \ #define EXTRA_CONSTRAINT(VALUE, C) \
((C) == 'Q' \ ((C) == 'Q' \
? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \ ? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
...@@ -630,6 +646,8 @@ extern enum reg_class m32r_regno_reg_class[]; ...@@ -630,6 +646,8 @@ extern enum reg_class m32r_regno_reg_class[];
: (C) == 'R' \ : (C) == 'R' \
? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \ ? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
|| addr32_operand (VALUE, VOIDmode)) \ || addr32_operand (VALUE, VOIDmode)) \
: (C) == 'S' \
? ((GET_CODE (VALUE) == CONST_INT) && INVERTED_SIGNED_8BIT (INTVAL (VALUE))) \
: 0) : 0)
/* Stack layout and stack pointer usage. */ /* Stack layout and stack pointer usage. */
...@@ -717,6 +735,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size) ...@@ -717,6 +735,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
#define CARRY_REGNUM 17 #define CARRY_REGNUM 17
#define M32R_MAX_INT_REGS 16 #define M32R_MAX_INT_REGS 16
#define GPR_P(REGNO) ((unsigned) (REGNO) < M32R_MAX_INT_REGS) #define GPR_P(REGNO) ((unsigned) (REGNO) < M32R_MAX_INT_REGS)
/* Eliminating the frame and arg pointers. */ /* Eliminating the frame and arg pointers. */
...@@ -907,7 +926,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size) ...@@ -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 compiler when this occurs, and how many of the words should go in
registers. */ registers. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ #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 /* A C expression that indicates when an argument must be passed by
reference. If nonzero for an argument, a copy of that argument is reference. If nonzero for an argument, a copy of that argument is
...@@ -1218,9 +1237,8 @@ do { \ ...@@ -1218,9 +1237,8 @@ do { \
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */ return the mode to be used for the comparison. */
extern enum machine_mode m32r_select_cc_mode ();
#define SELECT_CC_MODE(OP, X, Y) \ #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 /* Return non-zero if SELECT_CC_MODE will never return MODE for a
floating point inequality comparison. */ floating point inequality comparison. */
...@@ -1313,6 +1331,38 @@ m32r_select_cc_mode (OP, X, Y) ...@@ -1313,6 +1331,38 @@ m32r_select_cc_mode (OP, X, Y)
the improvement wasn't significant and in a couple of cases caused a the improvement wasn't significant and in a couple of cases caused a
significant de-optimization. */ significant de-optimization. */
/* #define ENABLE_REGMOVE_PASS */ /* #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. */ /* Section selection. */
...@@ -1344,7 +1394,7 @@ DTORS_SECTION_FUNCTION \ ...@@ -1344,7 +1394,7 @@ DTORS_SECTION_FUNCTION \
SDATA_SECTION_FUNCTION \ SDATA_SECTION_FUNCTION \
SBSS_SECTION_FUNCTION SBSS_SECTION_FUNCTION
#define SDATA_SECTION_FUNCTION \ #define SDATA_SECTION_FUNCTION \
void \ void \
sdata_section () \ sdata_section () \
{ \ { \
...@@ -1355,7 +1405,7 @@ sdata_section () \ ...@@ -1355,7 +1405,7 @@ sdata_section () \
} \ } \
} \ } \
#define SBSS_SECTION_FUNCTION \ #define SBSS_SECTION_FUNCTION \
void \ void \
sbss_section () \ sbss_section () \
{ \ { \
...@@ -1429,7 +1479,6 @@ extern void m32r_select_section (); ...@@ -1429,7 +1479,6 @@ extern void m32r_select_section ();
|| MEDIUM_NAME_P (SYMBOL_NAME) \ || MEDIUM_NAME_P (SYMBOL_NAME) \
|| LARGE_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) #define ENCODE_SECTION_INFO(DECL) m32r_encode_section_info (DECL)
/* Decode SYM_NAME and store the real name part in VAR, sans /* Decode SYM_NAME and store the real name part in VAR, sans
...@@ -1487,7 +1536,6 @@ do { \ ...@@ -1487,7 +1536,6 @@ do { \
/* Control the assembler format that we output. */ /* Control the assembler format that we output. */
/* Output at beginning of assembler file. */ /* Output at beginning of assembler file. */
extern void m32r_asm_file_start ();
#define ASM_FILE_START(FILE) m32r_asm_file_start (FILE) #define ASM_FILE_START(FILE) m32r_asm_file_start (FILE)
/* A C string constant describing how to begin a comment in the target /* A C string constant describing how to begin a comment in the target
...@@ -1582,7 +1630,7 @@ do { \ ...@@ -1582,7 +1630,7 @@ do { \
#undef ASM_OUTPUT_LABELREF #undef ASM_OUTPUT_LABELREF
#define ASM_OUTPUT_LABELREF(FILE, NAME) \ #define ASM_OUTPUT_LABELREF(FILE, NAME) \
do { \ do { \
char *real_name; \ char * real_name; \
STRIP_NAME_ENCODING (real_name, (NAME)); \ STRIP_NAME_ENCODING (real_name, (NAME)); \
fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \ fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \
} while (0) } while (0)
...@@ -1713,8 +1761,6 @@ do { \ ...@@ -1713,8 +1761,6 @@ do { \
handling the required alignment of the variable. The alignment is handling the required alignment of the variable. The alignment is
specified as the number of bits. */ specified as the number of bits. */
extern void sbss_section ();
#undef ASM_OUTPUT_ALIGNED_LOCAL #undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ #define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \ do { \
...@@ -1833,35 +1879,146 @@ do { \ ...@@ -1833,35 +1879,146 @@ do { \
/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS /* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
is a valid machine specific attribute for DECL. is a valid machine specific attribute for DECL.
The attributes in ATTRIBUTES have previously been assigned to TYPE. */ 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) \ #define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
m32r_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 /* 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 incompatible, one if they are compatible, and two if they are
nearly compatible (which causes a warning to be generated). */ nearly compatible (which causes a warning to be generated). */
extern int m32r_comp_type_attributes ();
#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ #define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
m32r_comp_type_attributes (TYPE1, TYPE2) m32r_comp_type_attributes (TYPE1, TYPE2)
/* Give newly defined TYPE some default attributes. */ /* Give newly defined TYPE some default attributes. */
extern void m32r_set_default_type_attributes ();
#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \ #define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
m32r_set_default_type_attributes (TYPE) m32r_set_default_type_attributes (TYPE)
/* Define the information needed to generate branch and scc insns. This is /* 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 stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */ since it hasn't been defined! */
extern struct rtx_def *m32r_compare_op0, *m32r_compare_op1; extern struct rtx_def * m32r_compare_op0;
extern struct rtx_def * m32r_compare_op1;
/* Define the function that build the compare insn for scc and bcc. */
extern struct rtx_def *gen_compare ();
/* M32R function types. */ /* M32R function types. */
enum m32r_function_type { enum m32r_function_type
{
M32R_FUNCTION_UNKNOWN, M32R_FUNCTION_NORMAL, M32R_FUNCTION_INTERRUPT M32R_FUNCTION_UNKNOWN, M32R_FUNCTION_NORMAL, M32R_FUNCTION_INTERRUPT
}; };
#define M32R_INTERRUPT_P(TYPE) \ #define M32R_INTERRUPT_P(TYPE) \
((TYPE) == M32R_FUNCTION_INTERRUPT) ((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)
;; Machine description of the Mitsubishi M32R cpu for GNU C compiler ;; 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. ;; This file is part of GNU CC.
...@@ -65,11 +65,135 @@ ...@@ -65,11 +65,135 @@
(define_asm_attributes (define_asm_attributes
[(set_attr "length" "4") [(set_attr "length" "4")
(set_attr "type" "multi")]) (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 ;; Function units of the M32R
;; Units that take one cycle do not need to be specified. ;; 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}]) ;; {ready-delay} {issue-delay} [{conflict-list}])
;; References to loaded registers should wait a cycle. ;; References to loaded registers should wait a cycle.
...@@ -94,6 +218,7 @@ ...@@ -94,6 +218,7 @@
(not (eq_attr "length" "2")) (not (eq_attr "length" "2"))
1 0 1 0
[(eq_attr "length" "2")]) [(eq_attr "length" "2")])
;; Expand prologue as RTL ;; Expand prologue as RTL
;; ??? Unfinished. ;; ??? Unfinished.
...@@ -915,6 +1040,7 @@ ...@@ -915,6 +1040,7 @@
DONE; DONE;
}") }")
;; The cmp_xxx_insn patterns set the condition bit to the result of the ;; 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 ;; comparison. There isn't a "compare equal" instruction so cmp_eqsi_insn
;; is quite inefficient. However, it is rarely used. ;; is quite inefficient. However, it is rarely used.
...@@ -924,10 +1050,23 @@ ...@@ -924,10 +1050,23 @@
(eq:CC (match_operand:SI 0 "register_operand" "r,r") (eq:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_cmp_int16_operand" "r,P"))) (match_operand:SI 1 "reg_or_cmp_int16_operand" "r,P")))
(clobber (match_scratch:SI 2 "=&r,&r"))] (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 "type" "compare,compare")
(set_attr "length" "8,8")]) (set_attr "length" "8,8")])
...@@ -939,17 +1078,23 @@ ...@@ -939,17 +1078,23 @@
"@ "@
cmp %0,%1 cmp %0,%1
cmpi %0,%#%1" cmpi %0,%#%1"
[(set_attr "type" "compare")]) [(set_attr "type" "compare,compare")
(set_attr "length" "4,6")])
(define_insn "cmp_ltusi_insn" (define_insn "cmp_ltusi_insn"
[(set (reg:CC 17) [(set (reg:CC 17)
(ltu:CC (match_operand:SI 0 "register_operand" "r,r") (ltu:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_uint16_operand" "r,K")))] (match_operand:SI 1 "reg_or_uint16_operand" "r,K")))]
"" ""
"@ "*
cmpu %0,%1 {
cmpui %0,%#%1" if (which_alternative == 0)
[(set_attr "type" "compare")]) 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 ;; reg == small constant comparisons are best handled by putting the result
;; of the comparison in a tmp reg and then using beqz/bnez. ;; of the comparison in a tmp reg and then using beqz/bnez.
...@@ -957,13 +1102,15 @@ ...@@ -957,13 +1102,15 @@
;; it contains 0/non-zero. ;; it contains 0/non-zero.
(define_insn "cmp_ne_small_const_insn" (define_insn "cmp_ne_small_const_insn"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r,r")
(ne:SI (match_operand:SI 1 "register_operand" "r") (ne:SI (match_operand:SI 1 "register_operand" "0,r")
(match_operand:SI 2 "cmp_int16_operand" "P")))] (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 "type" "compare")
(set_attr "length" "4")]) (set_attr "length" "2,4")])
;; These control RTL generation for conditional jump insns. ;; These control RTL generation for conditional jump insns.
...@@ -975,7 +1122,7 @@ ...@@ -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" (define_expand "bne"
...@@ -986,7 +1133,7 @@ ...@@ -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" (define_expand "bgt"
...@@ -997,7 +1144,7 @@ ...@@ -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" (define_expand "ble"
...@@ -1008,7 +1155,7 @@ ...@@ -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" (define_expand "bge"
...@@ -1019,7 +1166,7 @@ ...@@ -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" (define_expand "blt"
...@@ -1030,7 +1177,7 @@ ...@@ -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" (define_expand "bgtu"
...@@ -1041,7 +1188,7 @@ ...@@ -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" (define_expand "bleu"
...@@ -1052,7 +1199,7 @@ ...@@ -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" (define_expand "bgeu"
...@@ -1063,7 +1210,7 @@ ...@@ -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" (define_expand "bltu"
...@@ -1074,7 +1221,7 @@ ...@@ -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. ;; Now match both normal and inverted jump.
...@@ -1088,10 +1235,11 @@ ...@@ -1088,10 +1235,11 @@
"" ""
"* "*
{ {
if (GET_CODE (operands[1]) == NE) static char instruction[40];
return \"bc %l0\"; sprintf (instruction, \"%s%s %%l0\",
else (GET_CODE (operands[1]) == NE) ? \"bc\" : \"bnc\",
return \"bnc %l0\"; (get_attr_length (insn) == 2) ? \".s\" : \"\");
return instruction;
}" }"
[(set_attr "type" "branch") [(set_attr "type" "branch")
; We use 400/800 instead of 512,1024 to account for inaccurate insn ; We use 400/800 instead of 512,1024 to account for inaccurate insn
...@@ -1116,10 +1264,11 @@ ...@@ -1116,10 +1264,11 @@
"" ""
"* "*
{ {
if (GET_CODE (operands[1]) == EQ) static char instruction[40];
return \"bc %l0\"; sprintf (instruction, \"%s%s %%l0\",
else (GET_CODE (operands[1]) == EQ) ? \"bc\" : \"bnc\",
return \"bnc %l0\"; (get_attr_length (insn) == 2) ? \".s\" : \"\");
return instruction;
}" }"
[(set_attr "type" "branch") [(set_attr "type" "branch")
; We use 400/800 instead of 512,1024 to account for inaccurate insn ; We use 400/800 instead of 512,1024 to account for inaccurate insn
...@@ -1452,6 +1601,51 @@ ...@@ -1452,6 +1601,51 @@
"* return \"nop ; flush-icache\";" "* return \"nop ; flush-icache\";"
[(set_attr "type" "misc")]) [(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. ;; Split up troublesome insns for better scheduling.
;; Peepholes go at the end. ;; Peepholes go at the end.
...@@ -1467,3 +1661,46 @@ ...@@ -1467,3 +1661,46 @@
"st %1,@+%0" "st %1,@+%0"
[(set_attr "type" "store") [(set_attr "type" "store")
(set_attr "length" "2")]) (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) ...@@ -39,6 +39,7 @@ crtfini.o: $(srcdir)/config/m32r/initfini.c $(GCC_PASSES) $(CONFIG_H)
-DCRT_FINI -finhibit-size-directive -fno-inline-functions \ -DCRT_FINI -finhibit-size-directive -fno-inline-functions \
-g0 -c $(srcdir)/config/m32r/initfini.c -o crtfini.o -g0 -c $(srcdir)/config/m32r/initfini.c -o crtfini.o
# -mmodel={small,medium} requires separate libraries. # -mmodel={small,medium} requires separate libraries.
# We don't build libraries for the large model, instead we use the medium # 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 # libraries. The only difference is that the large model can handle jumps
...@@ -48,6 +49,7 @@ MULTILIB_OPTIONS = mmodel=small/mmodel=medium ...@@ -48,6 +49,7 @@ MULTILIB_OPTIONS = mmodel=small/mmodel=medium
MULTILIB_DIRNAMES = small medium MULTILIB_DIRNAMES = small medium
MULTILIB_MATCHES = mmodel?medium=mmodel?large MULTILIB_MATCHES = mmodel?medium=mmodel?large
# Set MULTILIB_EXTRA_OPTS so shipped libraries have small data in .sdata and # Set MULTILIB_EXTRA_OPTS so shipped libraries have small data in .sdata and
# SHN_M32R_SCOMMON. # SHN_M32R_SCOMMON.
# This is important for objects referenced in system header files. # This is important for objects referenced in system header files.
......
...@@ -4580,7 +4580,7 @@ fi ...@@ -4580,7 +4580,7 @@ fi
if [ x$enable_haifa = x ] if [ x$enable_haifa = x ]
then then
case $target in case $target in
alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*) alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-* | m32r*-*)
enable_haifa=yes;; enable_haifa=yes;;
esac esac
fi fi
......
...@@ -2891,7 +2891,7 @@ fi ...@@ -2891,7 +2891,7 @@ fi
if [[ x$enable_haifa = x ]] if [[ x$enable_haifa = x ]]
then then
case $target in case $target in
alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*) alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-* | m32r*-*)
enable_haifa=yes;; enable_haifa=yes;;
esac esac
fi fi
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment