update m32r port

From-SVN: r19465
This commit is contained in:
Michael Meissner 1998-04-28 05:58:21 +00:00 committed by Michael Meissner
parent 77be0cab5f
commit 2b7972b093
7 changed files with 943 additions and 146 deletions

View File

@ -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).

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, Mitsubishi M32R cpu.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (m32r)")
/* Switch Recognition by gcc.c. Add -G xx support */
#undef SWITCH_TAKES_ARG
@ -48,17 +49,18 @@ Boston, MA 02111-1307, USA. */
/* __M32R__ is defined by the existing compiler so we use that. */
#define CPP_PREDEFINES "-Acpu(m32r) -Amachine(m32r) -D__M32R__"
/* Additional flags for the preprocessor. */
#define CPP_SPEC ""
#define CC1_SPEC "%{G*}"
#undef ASM_SPEC
#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
@ -72,9 +74,11 @@ Boston, MA 02111-1307, USA. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC "%{!shared:crt0.o%s crtsysc.o%s} crtinit.o%s"
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtfini.o%s"
#undef LIB_SPEC
/* Run-time compilation parameters selecting different hardware subsets. */
@ -105,6 +109,10 @@ extern int target_flags;
#define TARGET_OLD_COMPARE_MASK 8
#define TARGET_OLD_COMPARE (target_flags & TARGET_OLD_COMPARE_MASK)
/* Target machine to compile for. */
#define TARGET_M32R 1
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
@ -147,6 +155,8 @@ extern int target_flags;
extern char *m32r_model_string;
extern char *m32r_sdata_string;
#define TARGET_OPTIONS \
{ \
{ "model=", &m32r_model_string }, \
@ -239,10 +249,10 @@ extern enum m32r_sdata m32r_sdata;
#define M32R_SDATA_DEFAULT "none"
/* Define this macro as a C expression for the initializer of an array of
string to tell the driver program which options are defaults for this
strings to tell the driver program which options are defaults for this
target and thus do not need to be handled specially when using
`MULTILIB_OPTIONS'. */
#define MULTILIB_DEFAULTS { "mmodel=small" }
#define MULTILIB_DEFAULTS { "mmodel=small", "m32r" }
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
@ -253,8 +263,6 @@ extern enum m32r_sdata m32r_sdata;
Don't use this macro to turn on various extra optimizations for
`-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
extern void m32r_init ();
#define OVERRIDE_OPTIONS \
do { \
/* These need to be done at start up. It's convenient to do them here. */ \
@ -404,7 +412,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */
#define FIRST_PSEUDO_REGISTER 18
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
@ -420,6 +428,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
16 - arg pointer
17 - carry flag
By default, the extension registers are not available. */
#define FIXED_REGISTERS \
@ -427,6 +436,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 0, 1, \
1, 0 }
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
@ -439,6 +449,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
/* Zero or more C statements that may conditionally modify two variables
`fixed_regs' and `call_used_regs' (both of type `char []') after they
have been initialized from the two preceding macros.
@ -531,11 +542,12 @@ enum reg_class {
#define REG_CLASS_CONTENTS \
{ {0}, {0x20000}, {0x1ffff}, {0x3ffff} }
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
extern enum reg_class m32r_regno_reg_class[];
extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
#define REGNO_REG_CLASS(REGNO) \
(m32r_regno_reg_class[REGNO])
@ -622,7 +634,11 @@ extern enum reg_class m32r_regno_reg_class[];
C. If C is not defined as an extra constraint, the value returned should
be 0 regardless of VALUE. */
/* Q is for symbolic addresses loadable with ld24.
R is for symbolic addresses when ld24 can't be used. */
R is for symbolic addresses when ld24 can't be used.
S is for an 8 bit signed integer in the range +128 to -127 */
#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128)
#define EXTRA_CONSTRAINT(VALUE, C) \
((C) == 'Q' \
? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
@ -630,6 +646,8 @@ extern enum reg_class m32r_regno_reg_class[];
: (C) == 'R' \
? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
|| addr32_operand (VALUE, VOIDmode)) \
: (C) == 'S' \
? ((GET_CODE (VALUE) == CONST_INT) && INVERTED_SIGNED_8BIT (INTVAL (VALUE))) \
: 0)
/* Stack layout and stack pointer usage. */
@ -717,6 +735,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
#define CARRY_REGNUM 17
#define M32R_MAX_INT_REGS 16
#define GPR_P(REGNO) ((unsigned) (REGNO) < M32R_MAX_INT_REGS)
/* Eliminating the frame and arg pointers. */
@ -907,7 +926,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
compiler when this occurs, and how many of the words should go in
registers. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
function_arg_partial_nregs (&CUM, (int)MODE, TYPE, NAMED)
/* A C expression that indicates when an argument must be passed by
reference. If nonzero for an argument, a copy of that argument is
@ -1218,9 +1237,8 @@ do { \
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
extern enum machine_mode m32r_select_cc_mode ();
#define SELECT_CC_MODE(OP, X, Y) \
m32r_select_cc_mode (OP, X, Y)
((enum machine_mode)m32r_select_cc_mode ((int)OP, X, Y))
/* Return non-zero if SELECT_CC_MODE will never return MODE for a
floating point inequality comparison. */
@ -1313,6 +1331,38 @@ m32r_select_cc_mode (OP, X, Y)
the improvement wasn't significant and in a couple of cases caused a
significant de-optimization. */
/* #define ENABLE_REGMOVE_PASS */
/* A C statement (sans semicolon) to update the integer variable COST based on
the relationship between INSN that is dependent on DEP_INSN through the
dependence LINK. The default is to make no adjustment to COST. This can be
used for example to specify to the scheduler that an output- or
anti-dependence does not incur the same cost as a data-dependence. */
/* #define ADJUST_COST(INSN,LINK,DEP_INSN,COST) \
(COST) = m32r_adjust_cost (INSN, LINK, DEP_INSN, COST) */
/* A C statement (sans semicolon) to update the integer scheduling
priority `INSN_PRIORITY(INSN)'. Reduce the priority to execute
the INSN earlier, increase the priority to execute INSN later.
Do not define this macro if you do not need to adjust the
scheduling priorities of insns. */
/* #define ADJUST_PRIORITY (INSN) */
/* Macro to determine whether the Haifa scheduler is used. */
#ifdef HAIFA
#define HAIFA_P 1
#else
#define HAIFA_P 0
#endif
/* Indicate how many instructions can be issued at the same time. */
#define ISSUE_RATE 2
/* When the `length' insn attribute is used, this macro specifies the
value to be assigned to the address of the first insn in a
function. If not specified, 0 is used. */
#define FIRST_INSN_ADDRESS m32r_first_insn_address ()
/* Section selection. */
@ -1344,7 +1394,7 @@ DTORS_SECTION_FUNCTION \
SDATA_SECTION_FUNCTION \
SBSS_SECTION_FUNCTION
#define SDATA_SECTION_FUNCTION \
#define SDATA_SECTION_FUNCTION \
void \
sdata_section () \
{ \
@ -1355,7 +1405,7 @@ sdata_section () \
} \
} \
#define SBSS_SECTION_FUNCTION \
#define SBSS_SECTION_FUNCTION \
void \
sbss_section () \
{ \
@ -1429,7 +1479,6 @@ extern void m32r_select_section ();
|| MEDIUM_NAME_P (SYMBOL_NAME) \
|| LARGE_NAME_P (SYMBOL_NAME))
extern void m32r_encode_section_info ();
#define ENCODE_SECTION_INFO(DECL) m32r_encode_section_info (DECL)
/* Decode SYM_NAME and store the real name part in VAR, sans
@ -1487,7 +1536,6 @@ do { \
/* Control the assembler format that we output. */
/* Output at beginning of assembler file. */
extern void m32r_asm_file_start ();
#define ASM_FILE_START(FILE) m32r_asm_file_start (FILE)
/* A C string constant describing how to begin a comment in the target
@ -1582,7 +1630,7 @@ do { \
#undef ASM_OUTPUT_LABELREF
#define ASM_OUTPUT_LABELREF(FILE, NAME) \
do { \
char *real_name; \
char * real_name; \
STRIP_NAME_ENCODING (real_name, (NAME)); \
fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \
} while (0)
@ -1713,8 +1761,6 @@ do { \
handling the required alignment of the variable. The alignment is
specified as the number of bits. */
extern void sbss_section ();
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
@ -1833,35 +1879,146 @@ do { \
/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
is a valid machine specific attribute for DECL.
The attributes in ATTRIBUTES have previously been assigned to TYPE. */
extern int m32r_valid_machine_attribute ();
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
m32r_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
/* A C expression that returns zero if the attributes on TYPE1 and TYPE2 are
incompatible, one if they are compatible, and two if they are
nearly compatible (which causes a warning to be generated). */
extern int m32r_comp_type_attributes ();
#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
m32r_comp_type_attributes (TYPE1, TYPE2)
/* Give newly defined TYPE some default attributes. */
extern void m32r_set_default_type_attributes ();
#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
m32r_set_default_type_attributes (TYPE)
/* Define the information needed to generate branch and scc insns. This is
stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */
extern struct rtx_def *m32r_compare_op0, *m32r_compare_op1;
/* Define the function that build the compare insn for scc and bcc. */
extern struct rtx_def *gen_compare ();
extern struct rtx_def * m32r_compare_op0;
extern struct rtx_def * m32r_compare_op1;
/* M32R function types. */
enum m32r_function_type {
enum m32r_function_type
{
M32R_FUNCTION_UNKNOWN, M32R_FUNCTION_NORMAL, M32R_FUNCTION_INTERRUPT
};
#define M32R_INTERRUPT_P(TYPE) \
((TYPE) == M32R_FUNCTION_INTERRUPT)
/* Compute the type of a function from its DECL. */
enum m32r_function_type m32r_compute_function_type ();
/* Define this if you have defined special-purpose predicates in the
file `MACHINE.c'. This macro is called within an initializer of an
array of structures. The first field in the structure is the name
of a predicate and the second field is an array of rtl codes. For
each predicate, list all rtl codes that can be in expressions
matched by the predicate. The list should have a trailing comma. */
#define PREDICATE_CODES \
{ "conditional_move_operand", { REG, SUBREG, CONST_INT }}, \
{ "carry_compare_operand", { EQ, NE }}, \
{ "eqne_comparison_operator", { EQ, NE }}, \
{ "signed_comparison_operator", { EQ, NE, LT, LE, GT, GE }}, \
{ "move_dest_operand", { REG, SUBREG, MEM }}, \
{ "move_src_operand", { REG, SUBREG, MEM, CONST_INT, \
CONST_DOUBLE, LABEL_REF, CONST, \
SYMBOL_REF }}, \
{ "move_double_src_operand", { REG, SUBREG, MEM, CONST_INT, \
CONST_DOUBLE }}, \
{ "two_insn_const_operand", { CONST_INT }}, \
{ "symbolic_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
{ "reg_or_int16_operand", { REG, SUBREG, CONST_INT }}, \
{ "reg_or_uint16_operand", { REG, SUBREG, CONST_INT }}, \
{ "reg_or_cmp_int16_operand", { REG, SUBREG, CONST_INT }}, \
{ "reg_or_zero_operand", { REG, SUBREG, CONST_INT }}, \
{ "cmp_int16_operand", { CONST_INT }}, \
{ "call_address_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
{ "small_insn_p", { INSN, CALL_INSN, JUMP_INSN }}, \
{ "large_insn_p", { INSN, CALL_INSN, JUMP_INSN }},
/* Functions declared in m32r.c */
#ifndef PROTO
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#define PROTO(ARGS) ARGS
#else
#define PROTO(ARGS) ()
#endif
#endif
#ifdef BUFSIZE /* stdio.h has been included, ok to use FILE * */
#define STDIO_PROTO(ARGS) PROTO(ARGS)
#else
#define STDIO_PROTO(ARGS) ()
#endif
#ifndef TREE_CODE
union tree_node;
#define Tree union tree_node *
#else
#define Tree tree
#endif
#ifndef RTX_CODE
struct rtx_def;
#define Rtx struct rtx_def *
#else
#define Rtx rtx
#endif
extern void sbss_section PROTO((void));
extern void sdata_section PROTO((void));
extern void m32r_init PROTO((void));
extern int m32r_valid_machine_decl_attribute PROTO((Tree, Tree, Tree, Tree));
extern int m32r_comp_type_attributes PROTO((Tree, Tree));
extern void m32r_select_section PROTO((Tree, int));
extern void m32r_encode_section_info PROTO((Tree));
extern void m32r_init_expanders PROTO((void));
extern int call_address_operand PROTO((Rtx, int));
extern int call_operand PROTO((Rtx, int));
extern int symbolic_operand PROTO((Rtx, int));
extern int small_data_operand PROTO((Rtx, int));
extern int addr24_operand PROTO((Rtx, int));
extern int addr32_operand PROTO((Rtx, int));
extern int call26_operand PROTO((Rtx, int));
extern int seth_add3_operand PROTO((Rtx, int));
extern int cmp_int16_operand PROTO((Rtx, int));
extern int uint16_operand PROTO((Rtx, int));
extern int reg_or_int16_operand PROTO((Rtx, int));
extern int reg_or_uint16_operand PROTO((Rtx, int));
extern int reg_or_cmp_nt16_operand PROTO((Rtx, int));
extern int two_insn_const_operand PROTO((Rtx, int));
extern int move_src_operand PROTO((Rtx, int));
extern int move_double_src_operand PROTO((Rtx, int));
extern int move_dest_operand PROTO((Rtx, int));
extern int easy_di_const PROTO((Rtx));
extern int easy_df_const PROTO((Rtx));
extern int eqne_comparison_operator PROTO((Rtx, int));
extern int signed_comparison_operator PROTO((Rtx, int));
extern int memreg_operand PROTO((Rtx, int));
extern int small_insn_p PROTO((Rtx, int));
extern int large_insn_p PROTO((Rtx, int));
extern int m32r_select_cc_mode PROTO((int, Rtx, Rtx));
extern Rtx gen_compare PROTO((int, Rtx, Rtx, int));
extern int function_arg_partial_nregs PROTO((CUMULATIVE_ARGS *,
int, Tree, int));
extern void m32r_setup_incoming_varargs PROTO((CUMULATIVE_ARGS *,
int, Tree, int *,
int));
extern int m32r_address_code PROTO((Rtx));
extern enum m32r_function_type m32r_compute_function_type
PROTO((Tree));
extern unsigned m32r_compute_frame_size PROTO((int));
extern int m32r_first_insn_address PROTO((void));
extern void m32r_output_function_prologue STDIO_PROTO((FILE *, int));
extern void m32r_output_function_epilogue STDIO_PROTO((FILE *, int));
extern void m32r_finalize_pic PROTO((void));
extern void m32r_initialize_trampoline PROTO((Rtx, Rtx, Rtx));
extern void m32r_asm_file_start STDIO_PROTO((FILE *));
extern void m32r_print_operand STDIO_PROTO((FILE *, Rtx, int));
extern void m32r_print_operand_address STDIO_PROTO((FILE *, Rtx));
extern int zero_and_one PROTO((Rtx, Rtx));
extern int conditional_move_operand PROTO((Rtx, int));
extern int carry_compare_operand PROTO((Rtx, int));
extern char *emit_cond_move PROTO((Rtx *, Rtx));
/* Needed by a peephole optimisation. */
#define PRESERVE_DEATH_INFO_REGNO_P(regno) (regno < FIRST_PSEUDO_REGISTER)

View File

@ -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")
]
)

View File

@ -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
View File

@ -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

View File

@ -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