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