diff options
author | Michael Meissner <meissner@cygnus.com> | 1998-05-08 15:46:05 +0000 |
---|---|---|
committer | Michael Meissner <meissner@gcc.gnu.org> | 1998-05-08 15:46:05 +0000 |
commit | 5b8ae21fa87d7beb5b400db9d7337d557b68854c (patch) | |
tree | bf9756cb245c791dc1d7ea52fb2c2cf210e23056 /gcc | |
parent | cf879efaf491d1baa09e884b2d5cf74e720a1c43 (diff) | |
download | gcc-5b8ae21fa87d7beb5b400db9d7337d557b68854c.zip gcc-5b8ae21fa87d7beb5b400db9d7337d557b68854c.tar.gz gcc-5b8ae21fa87d7beb5b400db9d7337d557b68854c.tar.bz2 |
Hunk of m32r changes
From-SVN: r19636
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 48 | ||||
-rw-r--r-- | gcc/config/m32r/m32r.c | 335 | ||||
-rw-r--r-- | gcc/config/m32r/m32r.h | 141 | ||||
-rw-r--r-- | gcc/config/m32r/m32r.md | 670 |
4 files changed, 722 insertions, 472 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ad7a87e..105e4f6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -3,6 +3,54 @@ Fri May 8 18:23:08 1998 Michael Meissner <meissner@cygnus.com> * final.c (final_scan_insn): Call fatal_insn instead of abort if we could not split an insn when required to. + * m32r.md ({add,sub}di3): Add define_splits and appropriate low + level insns. + (peepholes): Disable peepholes that call dead_or_set_p. + (movsi): Rewrite to handle addresses better after last change. + Add define_split to split load of addresses in large/medium modes. + (prologue): Call m32r_expand_prologue. + (movsi_{push,pop}): Generators for push/pop. + (movsi): Support PRE_{INC,DEC}, POST_INC. + (mov{di,df}): Rewrite. Always split the insns. + (movsf): Add define_split to get register load in correct mode. + (cmp_ne_small_const_insn): Use 'N' instead of 'S' constraint. + (attributes): Rewrite attributes so that type indicates both the + type and the length of the insn directly. + (all insns): Change to use new type attributes. + (debug): New attribute to convey whether -mdebug was used. + (opt_space): New attribute to convey whether -Os was used. + (function units): Loads are 3 cycles, not 2. Better classify all + insns into short/long. + (load/store/extend insns): Add separate case for load/store + indirect operations without an offset. + (divsi3): Division is a long operation, not short. + + * m32r.h (LEGITIMATE_LO_SUM_ADDRESS_P): Do not allow LO_SUM for + modes > 1 word. + (GO_IF_MODE_DEPENDENT_ADDRESS): LO_SUM is now mode dependent. + (CONST_OK_FOR_LETTER_P): Make 'N' handle reverse 8 bit compares. + (EXTRA_CONSTRAINT): Remove 'S' special support. Add 'U' for + operands with PRE_{INC,DEC}, POST_INC. + (FUNCTION_PROFILER): Call abort instead of doing nothing. + (GO_IF_LEGITIMATE_ADDRESS): Allow PRE_{INC,DEC}, POST_INC of + SImode variables. + (gen_split_move_double): Declare. + (EXTRA_CONSTRAINT): Add 'T' for memory reference with no offset. + + * m32r.c (gen_split_move_double): Fix typo. Also, don't call + emit_move_insn, build up SET's directly. + (toplevel): Include system.h, not stdio.h. + (move_double_src_operand): Allow any DF or DI mode constant. + (gen_split_move_double): Split moves of DI or DF values into the + appropriate moves, loads, or stores. Don't handle use of auto + inc/dec if using dead index. Do handle overlapping moves, etc. + (m32r_frame_info): Remove prologue_size field. + (m32r_compute_frame_size): Don't calculate prologue size. + (m32r_output_function_prologue): Change to pretty much a NOP. + (m32r_expand_prologue): Expand prologue as a series of INSNs. + (m32r_print_operand): Add support for PRE_{INC,DEC}, POST_INC. + (m32r_print_operand_address): Ditto. + Fri May 8 14:13:21 1998 H.J. Lu (hjl@gnu.org) * reload1.c (emit_reload_insns): When performing expensive diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c index 3f80057..a667dbd 100644 --- a/gcc/config/m32r/m32r.c +++ b/gcc/config/m32r/m32r.c @@ -19,7 +19,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" -#include <stdio.h> +#include "system.h" #include "tree.h" #include "rtl.h" #include "regs.h" @@ -729,10 +729,7 @@ move_double_src_operand (op, int_mode) { case CONST_INT : case CONST_DOUBLE : - if (mode == DFmode) - return easy_df_const (op); - else - return easy_di_const (op); + return 1; case REG : return register_operand (op, mode); case SUBREG : @@ -1115,6 +1112,123 @@ gen_compare (int_code, x, y, need_compare) return gen_rtx (branch_code, VOIDmode, cc_reg, CONST0_RTX (mode)); } +/* Split a 2 word move (DI or DF) into component parts. */ + +rtx +gen_split_move_double (operands) + rtx operands[]; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx dest = operands[0]; + rtx src = operands[1]; + rtx val; + + start_sequence (); + if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG) + { + /* reg = reg */ + if (GET_CODE (src) == REG || GET_CODE (src) == SUBREG) + { + /* We normally copy the low-numbered register first. However, if + the first register operand 0 is the same as the second register of + operand 1, we must copy in the opposite order. */ + int reverse = (REGNO (operands[0]) == REGNO (operands[1]) + 1); + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, reverse, TRUE, mode), + operand_subword (src, reverse, TRUE, mode))); + + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, !reverse, TRUE, mode), + operand_subword (src, !reverse, TRUE, mode))); + } + + /* reg = constant */ + else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE) + { + rtx words[2]; + split_double (src, &words[0], &words[1]); + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, 0, TRUE, mode), + words[0])); + + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, 1, TRUE, mode), + words[1])); + } + + /* reg = mem */ + else if (GET_CODE (src) == MEM) + { + /* If the high-address word is used in the address, we must load it + last. Otherwise, load it first. */ + rtx addr = XEXP (src, 0); + int reverse = (refers_to_regno_p (REGNO (dest), REGNO (dest)+1, + addr, 0) != 0); + + /* We used to optimize loads from single registers as + + ld r1,r3+; ld r2,r3 + + if r3 were not used subsequently. However, the REG_NOTES aren't + propigated correctly by the reload phase, and it can cause bad + code to be generated. We could still try: + + ld r1,r3+; ld r2,r3; addi r3,-4 + + which saves 2 bytes and doesn't force longword alignment. */ + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, reverse, TRUE, mode), + change_address (src, SImode, + plus_constant (addr, + reverse * UNITS_PER_WORD)))); + + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, !reverse, TRUE, mode), + change_address (src, SImode, + plus_constant (addr, + (!reverse) * UNITS_PER_WORD)))); + } + + else + abort (); + } + + /* mem = reg */ + /* We used to optimize loads from single registers as + + st r1,r3; st r2,+r3 + + if r3 were not used subsequently. However, the REG_NOTES aren't + propigated correctly by the reload phase, and it can cause bad + code to be generated. We could still try: + + st r1,r3; st r2,+r3; addi r3,-4 + + which saves 2 bytes and doesn't force longword alignment. */ + else if (GET_CODE (dest) == MEM + && (GET_CODE (src) == REG || GET_CODE (src) == SUBREG)) + { + rtx addr = XEXP (dest, 0); + + emit_insn (gen_rtx_SET (VOIDmode, + change_address (dest, SImode, addr), + operand_subword (src, 0, TRUE, mode))); + + emit_insn (gen_rtx_SET (VOIDmode, + change_address (dest, SImode, + plus_constant (addr, UNITS_PER_WORD)), + operand_subword (src, 1, TRUE, mode))); + } + + else + abort (); + + val = gen_sequence (); + end_sequence (); + return val; +} + + /* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */ int @@ -1298,7 +1412,6 @@ 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 */ @@ -1322,7 +1435,7 @@ static struct m32r_frame_info zero_frame_info; && (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p))) #define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM]) -#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM]) +#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM] || profile_flag) #define SHORT_INSN_SIZE 2 /* size of small instructions */ #define LONG_INSN_SIZE 4 /* size of long instructions */ @@ -1338,7 +1451,7 @@ m32r_compute_frame_size (size) { int regno; unsigned int total_size, var_size, args_size, pretend_size, extra_size; - unsigned int reg_size, prolog_size, frame_size; + unsigned int reg_size, frame_size; unsigned int gmask; enum m32r_function_type fn_type; int interrupt_p; @@ -1349,7 +1462,6 @@ 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 @@ -1379,33 +1491,8 @@ 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; @@ -1413,7 +1500,6 @@ 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; @@ -1431,74 +1517,37 @@ m32r_first_insn_address () if (! current_frame_info.initialized) m32r_compute_frame_size (get_frame_size ()); - return current_frame_info.prolog_size; + return 0; } -/* 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. */ +/* Expand the m32r prologue as a series of insns. */ void -m32r_output_function_prologue (file, size) - FILE * file; - int size; +m32r_expand_prologue () { int regno; - int total_size, frame_size; - char *sp_str = reg_names[STACK_POINTER_REGNUM]; - char *fp_str = reg_names[FRAME_POINTER_REGNUM]; + int frame_size; unsigned int gmask = current_frame_info.gmask; - enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl); - /* If this is an interrupt handler, mark it as such. */ - if (M32R_INTERRUPT_P (fn_type)) - { - fprintf (file, "\t%s interrupt handler\n", - ASM_COMMENT_START); - } - - total_size = (! current_frame_info.initialized - ? m32r_compute_frame_size (size) - : current_frame_info.total_size); + if (! current_frame_info.initialized) + m32r_compute_frame_size (get_frame_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); + gmask = current_frame_info.gmask; /* These cases shouldn't happen. Catch them now. */ - if (total_size == 0 && gmask) + if (current_frame_info.total_size == 0 && gmask) abort (); -#if 1 /* Allocate space for register arguments if this is a variadic function. */ if (current_frame_info.pretend_size != 0) - fprintf (file, "\taddi %s,%s%d\n", - sp_str, IMMEDIATE_PREFIX, - -current_frame_info.pretend_size); -#else - /* If there are unnamed args in registers, save them. */ - if (current_function_stdarg || current_function_varargs) - { - int i; - fprintf (file, "\taddi %s,%s%d\n", - sp_str, IMMEDIATE_PREFIX, - - M32R_MAX_PARM_REGS * UNITS_PER_WORD); - for (i = 0; i < M32R_MAX_PARM_REGS; ++i) - fprintf (file, "\tst %s,@(sp,%d)\n", - reg_names[i], i * UNITS_PER_WORD); - } -#endif + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-current_frame_info.pretend_size))); /* Save any registers we need to and set up fp. */ if (current_frame_info.save_fp) - fprintf (file, "\tpush %s\n", fp_str); + emit_insn (gen_movsi_push (stack_pointer_rtx, frame_pointer_rtx)); gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK); @@ -1507,33 +1556,68 @@ m32r_output_function_prologue (file, size) for (regno = 0; regno <= M32R_MAX_INT_REGS; ++regno) { if ((gmask & (1 << regno)) != 0) - fprintf (file, "\tpush %s\n", reg_names[regno]); + emit_insn (gen_movsi_push (stack_pointer_rtx, + gen_rtx_REG (Pmode, regno))); } if (current_frame_info.save_lr) - fprintf (file, "\tpush %s\n", reg_names[RETURN_ADDR_REGNUM]); + emit_insn (gen_movsi_push (stack_pointer_rtx, + gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM))); /* Allocate the stack frame. */ - frame_size = total_size - (current_frame_info.pretend_size - + current_frame_info.reg_size); + frame_size = (current_frame_info.total_size + - (current_frame_info.pretend_size + + current_frame_info.reg_size)); + if (frame_size == 0) ; /* nothing to do */ - else if (frame_size <= 128) - fprintf (file, "\taddi %s,%s%d\n", - sp_str, IMMEDIATE_PREFIX, -frame_size); else if (frame_size <= 32768) - fprintf (file, "\tadd3 %s,%s,%s%d\n", - sp_str, sp_str, IMMEDIATE_PREFIX, -frame_size); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-frame_size))); else - fprintf (file, "\tld24 %s,%s%d\n\tsub %s,%s\n", - reg_names[PROLOGUE_TMP_REGNUM], - IMMEDIATE_PREFIX, frame_size, - sp_str, reg_names[PROLOGUE_TMP_REGNUM]); + { + rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM); + emit_insn (gen_movsi (tmp, GEN_INT (frame_size))); + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); + } if (frame_pointer_needed) - fprintf (file, "\tmv %s,%s\n", fp_str, sp_str); + emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); + + if (profile_flag || profile_block_flag) + emit_insn (gen_blockage ()); +} + + +/* 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) + FILE * file; + int size; +{ + enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl); + + /* If this is an interrupt handler, mark it as such. */ + if (M32R_INTERRUPT_P (fn_type)) + { + fprintf (file, "\t%s interrupt handler\n", + ASM_COMMENT_START); + } + + if (! current_frame_info.initialized) + m32r_compute_frame_size (size); - fprintf (file, "\t%s END PROLOGUE\n", ASM_COMMENT_START); + /* This is only for the human reader. */ + fprintf (file, + "\t%s PROLOGUE, vars= %d, regs= %d, args= %d, extra= %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); } /* Do any necessary cleanup after a function to restore stack, frame, @@ -1695,6 +1779,8 @@ m32r_print_operand (file, x, code) rtx x; int code; { + rtx addr; + switch (code) { case 'R' : @@ -1866,16 +1952,34 @@ m32r_print_operand (file, x, code) break; case MEM : - fprintf (file, "@("); - if (GET_CODE (XEXP (x, 0)) == PRE_INC) - output_address (plus_constant (XEXP (XEXP (x, 0), 0), - GET_MODE_SIZE (GET_MODE (x)))); - else if (GET_CODE (XEXP (x, 0)) == PRE_DEC) - output_address (plus_constant (XEXP (XEXP (x, 0), 0), - - GET_MODE_SIZE (GET_MODE (x)))); + addr = XEXP (x, 0); + if (GET_CODE (addr) == PRE_INC) + { + if (GET_CODE (XEXP (addr, 0)) != REG) + abort (); + + fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]); + } + else if (GET_CODE (addr) == PRE_DEC) + { + if (GET_CODE (XEXP (addr, 0)) != REG) + abort (); + + fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]); + } + else if (GET_CODE (addr) == POST_INC) + { + if (GET_CODE (XEXP (addr, 0)) != REG) + abort (); + + fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]); + } else - output_address (XEXP (x, 0)); - fputc (')', file); + { + fputs ("@(", file); + output_address (XEXP (x, 0)); + fputc (')', file); + } break; case CONST_DOUBLE : @@ -1975,11 +2079,16 @@ m32r_print_operand_address (file, addr) fputs (reg_names[REGNO (XEXP (addr, 0))], file); break; - case PRE_INC : - case PRE_DEC : - /* We shouldn't get here as we've lost the mode of the memory object - (which says how much to inc/dec by). */ - abort (); + case PRE_INC : /* Assume SImode */ + fprintf (file, "+%s", reg_names[REGNO (XEXP (addr, 0))]); + break; + + case PRE_DEC : /* Assume SImode */ + fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]); + break; + + case POST_INC : /* Assume SImode */ + fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]); break; default : diff --git a/gcc/config/m32r/m32r.h b/gcc/config/m32r/m32r.h index e5dfc20..4e14770 100644 --- a/gcc/config/m32r/m32r.h +++ b/gcc/config/m32r/m32r.h @@ -606,16 +606,17 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER]; #define INT32_P(X) ((X) >= (-(HOST_WIDE_INT) 0x7fffffff - 1) \ && (X) <= (unsigned HOST_WIDE_INT) 0xffffffff) #define UINT5_P(X) ((unsigned) (X) < 32) +#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128) -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ -((C) == 'I' ? INT8_P (VALUE) \ - : (C) == 'J' ? INT16_P (VALUE) \ - : (C) == 'K' ? UINT16_P (VALUE) \ - : (C) == 'L' ? UPPER16_P (VALUE) \ - : (C) == 'M' ? UINT24_P (VALUE) \ - : (C) == 'N' ? INT32_P (VALUE) \ - : (C) == 'O' ? UINT5_P (VALUE) \ - : (C) == 'P' ? CMP_INT16_P (VALUE) \ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ +((C) == 'I' ? INT8_P (VALUE) \ + : (C) == 'J' ? INT16_P (VALUE) \ + : (C) == 'K' ? UINT16_P (VALUE) \ + : (C) == 'L' ? UPPER16_P (VALUE) \ + : (C) == 'M' ? UINT24_P (VALUE) \ + : (C) == 'N' ? INVERTED_SIGNED_8BIT (VALUE) \ + : (C) == 'O' ? UINT5_P (VALUE) \ + : (C) == 'P' ? CMP_INT16_P (VALUE) \ : 0) /* Similar, but for floating constants, and defining letters G and H. @@ -623,8 +624,8 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER]; For the m32r, handle a few constants inline. ??? We needn't treat DI and DF modes differently, but for now we do. */ #define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ -((C) == 'G' ? easy_di_const (VALUE) \ - : (C) == 'H' ? easy_df_const (VALUE) \ +((C) == 'G' ? easy_di_const (VALUE) \ + : (C) == 'H' ? easy_df_const (VALUE) \ : 0) /* A C expression that defines the optional machine-dependent constraint @@ -635,19 +636,25 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER]; be 0 regardless of VALUE. */ /* Q is for symbolic addresses loadable with ld24. 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) \ - || addr24_operand (VALUE, VOIDmode)) \ - : (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))) \ + S is unused. + T is for indirect of a pointer. + U is for pushes and pops of the stack pointer. */ + +#define EXTRA_CONSTRAINT(VALUE, C) \ +((C) == 'Q' \ + ? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \ + || addr24_operand (VALUE, VOIDmode)) \ + : (C) == 'R' \ + ? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \ + || addr32_operand (VALUE, VOIDmode)) \ + : (C) == 'S' \ + ? 0 \ + : (C) == 'T' \ + ? (GET_CODE (VALUE) == MEM \ + && memreg_operand (VALUE, GET_MODE (VALUE))) \ + : (C) == 'U' \ + ? (GET_CODE (VALUE) == MEM \ + && PUSH_POP_P (GET_MODE (VALUE), XEXP (VALUE, 0))) \ : 0) /* Stack layout and stack pointer usage. */ @@ -1069,7 +1076,7 @@ m32r_output_function_epilogue (FILE, SIZE) /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ -#define FUNCTION_PROFILER(FILE, LABELNO) +#define FUNCTION_PROFILER(FILE, LABELNO) abort () /* Trampolines. */ @@ -1184,24 +1191,37 @@ do { \ (GET_CODE (X) == CONST_INT && INT16_P (INTVAL (X))) /* local to this file */ -#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \ -(GET_CODE (X) == PLUS \ - && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ +#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \ +(GET_CODE (X) == PLUS \ + && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ && RTX_OK_FOR_OFFSET_P (XEXP (X, 1))) /* local to this file */ -#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X) \ -(GET_CODE (X) == LO_SUM \ - && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ +/* For LO_SUM addresses, do not allow them if the MODE is > 1 word, + since more than one instruction will be required. */ +#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X) \ +(GET_CODE (X) == LO_SUM \ + && (MODE != BLKmode && GET_MODE_SIZE (MODE) <= UNITS_PER_WORD) \ + && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ && CONSTANT_P (XEXP (X, 1))) -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ -{ if (RTX_OK_FOR_BASE_P (X)) \ - goto ADDR; \ - if (LEGITIMATE_OFFSET_ADDRESS_P ((MODE), (X))) \ - goto ADDR; \ - if (LEGITIMATE_LO_SUM_ADDRESS_P ((MODE), (X))) \ - goto ADDR; \ +/* local to this file */ +/* Memory address that is a push/pop of the stack pointer. */ +#define PUSH_POP_P(MODE, X) \ +((MODE) == SImode \ + && (GET_CODE (X) == POST_INC \ + || GET_CODE (X) == PRE_INC \ + || GET_CODE (X) == PRE_DEC)) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (RTX_OK_FOR_BASE_P (X)) \ + goto ADDR; \ + if (LEGITIMATE_OFFSET_ADDRESS_P ((MODE), (X))) \ + goto ADDR; \ + if (LEGITIMATE_LO_SUM_ADDRESS_P ((MODE), (X))) \ + goto ADDR; \ + if (PUSH_POP_P ((MODE), (X))) \ + goto ADDR; \ } /* Try machine-dependent ways of modifying an illegitimate address @@ -1223,14 +1243,13 @@ do { \ /* Go to LABEL if ADDR (a legitimate address expression) has an effect that depends on the machine mode it is used for. */ -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ -do { \ - if (GET_CODE (ADDR) == PRE_DEC) \ - goto LABEL; \ - if (GET_CODE (ADDR) == PRE_INC) \ - goto LABEL; \ - if (GET_CODE (ADDR) == POST_INC) \ - goto LABEL; \ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ +do { \ + if (GET_CODE (ADDR) == PRE_DEC \ + || GET_CODE (ADDR) == PRE_INC \ + || GET_CODE (ADDR) == POST_INC \ + || GET_CODE (ADDR) == LO_SUM) \ + goto LABEL; \ } while (0) /* Condition code usage. */ @@ -1286,7 +1305,7 @@ do { \ /* Compute the cost of moving data between registers and memory. */ /* Memory is 3 times as expensive as registers. ??? Is that the right way to look at it? */ -#define MEMORY_MOVE_COST(MODE,CLASS,IN) \ +#define MEMORY_MOVE_COST(MODE,CLASS,IN_P) \ (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD ? 6 : 12) /* The cost of a branch insn. */ @@ -1355,7 +1374,10 @@ do { \ #define HAIFA_P 0 #endif -/* Indicate how many instructions can be issued at the same time. */ +/* Indicate how many instructions can be issued at the same time. + This is 1/2 of a lie. The m32r can issue only 1 long insn at + once, but 2. However doing so allows the scheduler to group + the two short insns together. */ #define ISSUE_RATE 2 /* When the `length' insn attribute is used, this macro specifies the @@ -1635,6 +1657,27 @@ do { \ fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \ } while (0) +/* CYGNUS LOCAL -- m32rx/meissner */ +/* For the m32r if -Os, don't force line number label to begin + at the beginning of the word. */ + +#undef ASM_OUTPUT_SOURCE_LINE +#define ASM_OUTPUT_SOURCE_LINE(file, line) \ +do \ + { \ + static int sym_lineno = 1; \ + fprintf (file, ".stabn 68,0,%d,.LM%d-", \ + line, sym_lineno); \ + assemble_name (file, \ + XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));\ + fprintf (file, \ + (optimize_size) ? "\n\t.debugsym .LM%d\n" : "\n.LM%d:\n", \ + sym_lineno); \ + sym_lineno += 1; \ + } \ +while (0) +/* END CYGNUS LOCAL -- m32rx/meissner */ + /* Store in OUTPUT a string (made with alloca) containing an assembler-name for a local static variable named NAME. LABELNO is an integer which is different for each call. */ @@ -1998,6 +2041,7 @@ 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 Rtx gen_split_move_double PROTO((Rtx *)); extern int function_arg_partial_nregs PROTO((CUMULATIVE_ARGS *, int, Tree, int)); extern void m32r_setup_incoming_varargs PROTO((CUMULATIVE_ARGS *, @@ -2008,6 +2052,7 @@ 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_expand_prologue 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)); diff --git a/gcc/config/m32r/m32r.md b/gcc/config/m32r/m32r.md index 49f71d6..3c49e54 100644 --- a/gcc/config/m32r/m32r.md +++ b/gcc/config/m32r/m32r.md @@ -24,33 +24,20 @@ ;; 0 - blockage ;; 1 - flush_icache ;; 2 - load_sda_base +;; 3 - setting carry in addx/subx instructions. ;; Insn type. Used to default other attribute values. -;; move4 = 4 byte move (define_attr "type" - "move,move4,load,store,unary,binary,compare,shift,mul,div,uncond_branch,branch,call,multi,misc" + "int2,int4,load2,load4,load8,store2,store4,store8,shift2,shift4,mul2,div4,uncond_branch,branch,call,multi,misc" (const_string "misc")) ;; Length in bytes. (define_attr "length" "" - (cond [(eq_attr "type" "move,unary,shift,mul,div") + (cond [(eq_attr "type" "int2,load2,store2,shift2,mul2") (const_int 2) - (eq_attr "type" "binary") - (if_then_else (match_operand 2 "register_operand" "") - (const_int 2) (const_int 4)) - - (eq_attr "type" "compare") - (if_then_else (match_operand 1 "register_operand" "") - (const_int 2) (const_int 4)) - - (eq_attr "type" "load") - (if_then_else (match_operand 1 "memreg_operand" "") - (const_int 2) (const_int 4)) - - (eq_attr "type" "store") - (if_then_else (match_operand 0 "memreg_operand" "") - (const_int 2) (const_int 4)) + (eq_attr "type" "int4,load4,store4,shift4,div4") + (const_int 4) (eq_attr "type" "multi") (const_int 8) @@ -69,10 +56,16 @@ ;; Whether an instruction is 16-bit or 32-bit (define_attr "insn_size" "short,long" - (if_then_else (eq_attr "length" "2") + (if_then_else (eq_attr "type" "int2,load2,store2,shift2,mul2") (const_string "short") (const_string "long"))) +(define_attr "debug" "no,yes" + (const (symbol_ref "(TARGET_DEBUG != 0)"))) + +(define_attr "opt_size" "no,yes" + (const (symbol_ref "(optimize_size != 0)"))) + (define_attr "m32r" "no,yes" (const (symbol_ref "(TARGET_M32R != 0)"))) @@ -196,39 +189,52 @@ ;; (define_function_unit {name} {multiplicity} {simulataneity} {test} ;; {ready-delay} {issue-delay} [{conflict-list}]) -;; References to loaded registers should wait a cycle. -;; Memory with load-delay of 1 (i.e. 2 cycle load). -(define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0) - ;; Hack to get GCC to better pack the instructions. ;; We pretend there is a separate long function unit that conflicts with ;; both the left and right 16 bit insn slots. -(define_function_unit "left" 1 1 - (eq_attr "length" "2") +(define_function_unit "short" 2 2 + (and (eq_attr "m32r" "yes") + (and (eq_attr "insn_size" "short") + (eq_attr "type" "!load2"))) 1 0 - [(not (eq_attr "length" "2"))]) + [(eq_attr "insn_size" "long")]) -(define_function_unit "right" 1 1 - (eq_attr "length" "2") - 1 0 - [(not (eq_attr "length" "2"))]) +(define_function_unit "short" 2 2 ;; load delay of 1 clock for mem execution + 1 clock for WB + (and (eq_attr "m32r" "yes") + (eq_attr "type" "load2")) + 3 0 + [(eq_attr "insn_size" "long")]) (define_function_unit "long" 1 1 - (not (eq_attr "length" "2")) + (and (eq_attr "m32r" "yes") + (and (eq_attr "insn_size" "long") + (eq_attr "type" "!load4,load8"))) 1 0 - [(eq_attr "length" "2")]) + [(eq_attr "insn_size" "short")]) + +(define_function_unit "long" 1 1 ;; load delay of 1 clock for mem execution + 1 clock for WB + (and (eq_attr "m32r" "yes") + (and (eq_attr "insn_size" "long") + (eq_attr "type" "load4,load8"))) + 3 0 + [(eq_attr "insn_size" "short")]) + + + +;; Instruction grouping ;; Expand prologue as RTL -;; ??? Unfinished. - -;(define_expand "prologue" -; [(const_int 1)] -; "" -; " -;{ -;}") +(define_expand "prologue" + [(const_int 1)] + "" + " +{ + m32r_expand_prologue (); + DONE; +}") + ;; Move instructions. ;; @@ -251,16 +257,19 @@ }") (define_insn "*movqi_insn" - [(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,r,m") - (match_operand:QI 1 "move_src_operand" "r,I,JQR,m,r"))] + [(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,r,r,T,m") + (match_operand:QI 1 "move_src_operand" "r,I,JQR,T,m,r,r"))] "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)" "@ mv %0,%1 ldi %0,%#%1 ldi %0,%#%1 ldub %0,%1 + ldub %0,%1 + stb %1,%0 stb %1,%0" - [(set_attr "type" "move,move,move4,load,store")]) + [(set_attr "type" "int2,int2,int4,load2,load4,store2,store4") + (set_attr "length" "2,2,4,2,4,2,4")]) (define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") @@ -275,8 +284,8 @@ }") (define_insn "*movhi_insn" - [(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,r,r,m") - (match_operand:HI 1 "move_src_operand" "r,I,JQR,K,m,r"))] + [(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,r,r,r,T,m") + (match_operand:HI 1 "move_src_operand" "r,I,JQR,K,T,m,r,r"))] "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)" "@ mv %0,%1 @@ -284,8 +293,23 @@ ldi %0,%#%1 ld24 %0,%#%1 lduh %0,%1 + lduh %0,%1 + sth %1,%0 sth %1,%0" - [(set_attr "type" "move,move,move4,move4,load,store")]) + [(set_attr "type" "int2,int2,int4,int4,load2,load4,store2,store4") + (set_attr "length" "2,2,4,4,2,4,2,4")]) + +(define_expand "movsi_push" + [(set (mem:SI (pre_dec:SI (match_operand:SI 0 "register_operand" ""))) + (match_operand:SI 1 "register_operand" ""))] + "" + "") + +(define_expand "movsi_pop" + [(set (match_operand:SI 0 "register_operand" "") + (mem:SI (post_inc:SI (match_operand:SI 1 "register_operand" ""))))] + "" + "") (define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") @@ -314,21 +338,60 @@ } }") -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,r,r,r,r,m") ;; ??? Do we need a const_double constraint here for large unsigned values? - (match_operand:SI 1 "move_src_operand" "r,I,J,MQ,L,N,m,r"))] +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,r,r,r,r,r,r,T,U,m") + (match_operand:SI 1 "move_src_operand" "r,I,J,MQ,L,n,T,U,m,r,r,r"))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" - "@ - mv %0,%1 - ldi %0,%#%1 ; %X1 - ldi %0,%#%1 ; %X1 - ld24 %0,%#%1 ; %X1 - seth %0,%#%T1 - seth %0,%#%T1\;or3 %0,%0,%#%B1 - ld %0,%1 - st %1,%0" - [(set_attr "type" "move,move,move4,move4,move4,multi,load,store")]) + "* +{ + if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == SUBREG) + { + switch (GET_CODE (operands[1])) + { + HOST_WIDE_INT value; + + default: + break; + + case REG: + case SUBREG: + return \"mv %0,%1\"; + + case MEM: + return \"ld %0,%1\"; + + case CONST_INT: + value = INTVAL (operands[1]); + if (INT16_P (value)) + return \"ldi %0,%#%1\\t; %X1\"; + + if (UINT24_P (value)) + return \"ld24 %0,%#%1\\t; %X1\"; + + if (UPPER16_P (value)) + return \"seth %0,%#%T1\\t; %X1\"; + + return \"#\"; + + case CONST: + case SYMBOL_REF: + case LABEL_REF: + if (TARGET_ADDR24) + return \"ld24 %0,%#%1\"; + + return \"#\"; + } + } + + else if (GET_CODE (operands[0]) == MEM + && (GET_CODE (operands[1]) == REG || GET_CODE (operands[1]) == SUBREG)) + return \"st %1,%0\"; + + fatal_insn (\"bad movsi insn\", insn); +}" + [(set_attr "type" "int2,int2,int4,int4,int4,multi,load2,load2,load4,store2,store2,store4") + (set_attr "length" "2,2,4,4,4,8,2,2,4,2,2,4")]) ; Try to use a four byte / two byte pair for constants not loadable with ; ldi, ld24, seth. @@ -376,6 +439,17 @@ operands[3] = GEN_INT ((val) & 0xffff); }") +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "seth_add3_operand" "i"))] + "TARGET_ADDR32" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))] + "") + ;; Small data area support. ;; The address of _SDA_BASE_ is loaded into a register and all objects in ;; the small data area are indexed off that. This is done for each reference @@ -413,7 +487,8 @@ (unspec [(const_int 0)] 2))] "" "ld24 %0,#_SDA_BASE_" - [(set_attr "type" "move4")]) + [(set_attr "type" "int4") + (set_attr "length" "4")]) ;; 32 bit address support. @@ -438,7 +513,8 @@ (high:SI (match_operand 1 "symbolic_operand" "")))] "" "seth %0,%#shigh(%1)" - [(set_attr "type" "move4")]) + [(set_attr "type" "int4") + (set_attr "length" "4")]) (define_insn "lo_sum_si" [(set (match_operand:SI 0 "register_operand" "=r") @@ -446,7 +522,8 @@ (match_operand:SI 2 "immediate_operand" "in")))] "" "add3 %0,%1,%#%B2" - [(set_attr "length" "4")]) + [(set_attr "type" "int4") + (set_attr "length" "4")]) (define_expand "movdi" [(set (match_operand:DI 0 "general_operand" "") @@ -458,85 +535,22 @@ if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (DImode, operands[1]); - - if (CONSTANT_P (operands[1]) - && ! easy_di_const (operands[1])) - { - rtx mem = force_const_mem (DImode, operands[1]); - rtx reg = ((reload_in_progress || reload_completed) - ? copy_to_suggested_reg (XEXP (mem, 0), - gen_rtx (REG, Pmode, REGNO (operands[0])), - Pmode) - : force_reg (Pmode, XEXP (mem, 0))); - operands[1] = change_address (mem, DImode, reg); - } }") (define_insn "*movdi_insn" - [(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,m") - (match_operand:DI 1 "move_double_src_operand" "r,nG,m,r"))] + [(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,r,m") + (match_operand:DI 1 "move_double_src_operand" "r,nG,F,m,r"))] "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0 : - /* We normally copy the low-numbered register first. However, if - the first register operand 0 is the same as the second register of - operand 1, we must copy in the opposite order. */ - if (REGNO (operands[0]) == REGNO (operands[1]) + 1) - return \"mv %R0,%R1\;mv %0,%1\"; - else - return \"mv %0,%1\;mv %R0,%R1\"; - case 1 : - return \"#\"; - case 2 : - /* If the low-address word is used in the address, we must load it - last. Otherwise, load it first. Note that we cannot have - auto-increment in that case since the address register is known to be - dead. */ - if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, - operands [1], 0)) - { - return \"ld %R0,%R1\;ld %0,%1\"; - } - else - { - /* Try to use auto-inc addressing if we can. */ - if (GET_CODE (XEXP (operands[1], 0)) == REG - && dead_or_set_p (insn, XEXP (operands[1], 0))) - { - operands[1] = XEXP (operands[1], 0); - return \"ld %0,@%1+\;ld %R0,@%1\"; - } - return \"ld %0,%1\;ld %R0,%R1\"; - } - case 3 : - /* Try to use auto-inc addressing if we can. */ - if (GET_CODE (XEXP (operands[0], 0)) == REG - && dead_or_set_p (insn, XEXP (operands[0], 0))) - { - operands[0] = XEXP (operands[0], 0); - return \"st %1,@%0\;st %R1,@+%0\"; - } - return \"st %1,%0\;st %R1,%R0\"; - } -}" - [(set_attr "type" "multi,multi,multi,multi") - (set_attr "length" "4,4,6,6")]) + "#" + [(set_attr "type" "multi,multi,multi,load8,store8") + (set_attr "length" "4,4,16,6,6")]) (define_split - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "const_double_operand" ""))] + [(set (match_operand:DI 0 "move_dest_operand" "") + (match_operand:DI 1 "move_double_src_operand" ""))] "reload_completed" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] - " -{ - operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); - operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); - split_double (operands[1], operands + 4, operands + 5); -}") + [(match_dup 2)] + "operands[2] = gen_split_move_double (operands);") ;; Floating point move insns. @@ -553,37 +567,36 @@ }") (define_insn "*movsf_insn" - [(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,m") - (match_operand:SF 1 "move_src_operand" "r,F,m,r"))] + [(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,r,T,m") + (match_operand:SF 1 "move_src_operand" "r,F,T,m,r,r"))] "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)" - "* -{ - switch (which_alternative) - { - case 0 : - return \"mv %0,%1\"; - case 1 : - { - REAL_VALUE_TYPE r; - long l; - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); - REAL_VALUE_TO_TARGET_SINGLE (r, l); - operands[1] = GEN_INT (l); - if (l == 0) - return \"ldi %0,%#0\"; - if ((l & 0xffff) == 0) - return \"seth %0,%#%T1\"; - else - return \"seth %0,%#%T1\;or3 %0,%0,%#%B1\"; - } - case 2 : - return \"ld %0,%1\"; - case 3 : - return \"st %1,%0\"; - } -}" + "@ + mv %0,%1 + # + ld %0,%1 + ld %0,%1 + st %1,%0 + st %1,%0" ;; ??? Length of alternative 1 is either 2, 4 or 8. - [(set_attr "type" "move,multi,load,store")]) + [(set_attr "type" "int2,multi,load2,load4,store2,store4") + (set_attr "length" "2,8,2,4,2,4")]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "const_double_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 3))] + " +{ + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + operands[2] = operand_subword (operands[0], 0, 0, SFmode); + operands[3] = GEN_INT (l); +}") (define_expand "movdf" [(set (match_operand:DF 0 "general_operand" "") @@ -595,118 +608,57 @@ if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (DFmode, operands[1]); - - if (GET_CODE (operands[1]) == CONST_DOUBLE - && ! easy_df_const (operands[1])) - { - rtx mem = force_const_mem (DFmode, operands[1]); - rtx reg = ((reload_in_progress || reload_completed) - ? copy_to_suggested_reg (XEXP (mem, 0), - gen_rtx (REG, Pmode, REGNO (operands[0])), - Pmode) - : force_reg (Pmode, XEXP (mem, 0))); - operands[1] = change_address (mem, DFmode, reg); - } }") (define_insn "*movdf_insn" [(set (match_operand:DF 0 "move_dest_operand" "=r,r,r,m") - (match_operand:DF 1 "move_double_src_operand" "r,H,m,r"))] + (match_operand:DF 1 "move_double_src_operand" "r,F,m,r"))] "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" - "* -{ - switch (which_alternative) - { - case 0 : - /* We normally copy the low-numbered register first. However, if - the first register operand 0 is the same as the second register of - operand 1, we must copy in the opposite order. */ - if (REGNO (operands[0]) == REGNO (operands[1]) + 1) - return \"mv %R0,%R1\;mv %0,%1\"; - else - return \"mv %0,%1\;mv %R0,%R1\"; - case 1 : - { - REAL_VALUE_TYPE r; - long l[2]; - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); - REAL_VALUE_TO_TARGET_DOUBLE (r, l); - operands[1] = GEN_INT (l[0]); - if (l[0] == 0 && l[1] == 0) - return \"ldi %0,%#0\;ldi %R0,%#0\"; - else if (l[1] != 0) - abort (); - else if ((l[0] & 0xffff) == 0) - return \"seth %0,%#%T1\;ldi %R0,%#0\"; - else - abort (); - } - case 2 : - /* If the low-address word is used in the address, we must load it - last. Otherwise, load it first. Note that we cannot have - auto-increment in that case since the address register is known to be - dead. */ - if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, - operands [1], 0)) - { - return \"ld %R0,%R1\;ld %0,%1\"; - } - else - { - /* Try to use auto-inc addressing if we can. */ - if (GET_CODE (XEXP (operands[1], 0)) == REG - && dead_or_set_p (insn, XEXP (operands[1], 0))) - { - operands[1] = XEXP (operands[1], 0); - return \"ld %0,@%1+\;ld %R0,@%1\"; - } - return \"ld %0,%1\;ld %R0,%R1\"; - } - case 3 : - /* Try to use auto-inc addressing if we can. */ - if (GET_CODE (XEXP (operands[0], 0)) == REG - && dead_or_set_p (insn, XEXP (operands[0], 0))) - { - operands[0] = XEXP (operands[0], 0); - return \"st %1,@%0\;st %R1,@+%0\"; - } - return \"st %1,%0\;st %R1,%R0\"; - } -}" - [(set_attr "type" "multi,multi,multi,multi") - (set_attr "length" "4,6,6,6")]) + "#" + [(set_attr "type" "multi,multi,load8,store8") + (set_attr "length" "4,16,6,6")]) + +(define_split + [(set (match_operand:DF 0 "move_dest_operand" "") + (match_operand:DF 1 "move_double_src_operand" ""))] + "reload_completed" + [(match_dup 2)] + "operands[2] = gen_split_move_double (operands);") ;; Zero extension instructions. (define_insn "zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + [(set (match_operand:HI 0 "register_operand" "=r,r,r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,T,m")))] "" "@ and3 %0,%1,%#255 + ldub %0,%1 ldub %0,%1" - [(set_attr "type" "unary,load") - (set_attr "length" "4,*")]) + [(set_attr "type" "int4,load2,load4") + (set_attr "length" "4,2,4")]) (define_insn "zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,T,m")))] "" "@ and3 %0,%1,%#255 + ldub %0,%1 ldub %0,%1" - [(set_attr "type" "unary,load") - (set_attr "length" "4,*")]) + [(set_attr "type" "int4,load2,load4") + (set_attr "length" "4,2,4")]) (define_insn "zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,T,m")))] "" "@ and3 %0,%1,%#65535 + lduh %0,%1 lduh %0,%1" - [(set_attr "type" "unary,load") - (set_attr "length" "4,*")]) + [(set_attr "type" "int4,load2,load4") + (set_attr "length" "4,2,4")]) ;; Sign extension instructions. ;; ??? See v850.md. @@ -747,11 +699,12 @@ }") (define_insn "*sign_extendqihi2_insn" - [(set (match_operand:HI 0 "register_operand" "=r") - (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + [(set (match_operand:HI 0 "register_operand" "=r,r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "T,m")))] "" "ldb %0,%1" - [(set_attr "type" "load")]) + [(set_attr "type" "load2,load4") + (set_attr "length" "2,4")]) (define_expand "extendqisi2" [(set (match_operand:SI 0 "register_operand" "") @@ -777,11 +730,12 @@ }") (define_insn "*sign_extendqisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "T,m")))] "" "ldb %0,%1" - [(set_attr "type" "load")]) + [(set_attr "type" "load2,load4") + (set_attr "length" "2,4")]) (define_expand "extendhisi2" [(set (match_operand:SI 0 "register_operand" "") @@ -807,11 +761,12 @@ }") (define_insn "*sign_extendhisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=r") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "T,m")))] "" "ldh %0,%1" - [(set_attr "type" "load")]) + [(set_attr "type" "load2,load4") + (set_attr "length" "2,4")]) ;; Arithmetic instructions. @@ -828,7 +783,7 @@ add %0,%2 addi %0,%#%2 add3 %0,%1,%#%2" - [(set_attr "type" "binary") + [(set_attr "type" "int2,int2,int4") (set_attr "length" "2,2,4")]) ;(define_split @@ -849,21 +804,69 @@ (match_operand:DI 2 "register_operand" "r"))) (clobber (reg:CC 17))] "" - "* -{ - /* ??? The cmp clears the condition bit. Can we speed up somehow? */ - return \"cmp %L0,%L0\;addx %L0,%L2\;addx %H0,%H2\"; -}" - [(set_attr "type" "binary") + "#" + [(set_attr "type" "multi") (set_attr "length" "6")]) +;; ??? The cmp clears the condition bit. Can we speed up somehow? +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (match_operand 3 "" ""))] + "reload_completed" + [(parallel [(set (match_dup 3) + (const_int 0)) + (use (match_dup 4))]) + (parallel [(set (match_dup 4) + (plus:SI (match_dup 4) + (plus:SI (match_dup 5) + (match_dup 3)))) + (set (match_dup 3) + (unspec [(const_int 0)] 3))]) + (parallel [(set (match_dup 6) + (plus:SI (match_dup 6) + (plus:SI (match_dup 7) + (match_dup 3)))) + (set (match_dup 3) + (unspec [(const_int 0)] 3))])] + " +{ + operands[4] = operand_subword (operands[0], (WORDS_BIG_ENDIAN != 0), 0, DImode); + operands[5] = operand_subword (operands[2], (WORDS_BIG_ENDIAN != 0), 0, DImode); + operands[6] = operand_subword (operands[0], (WORDS_BIG_ENDIAN == 0), 0, DImode); + operands[7] = operand_subword (operands[2], (WORDS_BIG_ENDIAN == 0), 0, DImode); +}") + +(define_insn "*clear_c" + [(set (reg:CC 17) + (const_int 0)) + (use (match_operand:SI 0 "register_operand" "r"))] + "" + "cmp %0,%0" + [(set_attr "type" "int2") + (set_attr "length" "2")]) + +(define_insn "*add_carry" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "%0") + (plus:SI (match_operand:SI 2 "register_operand" "r") + (reg:CC 17)))) + (set (reg:CC 17) + (unspec [(const_int 0)] 3))] + "" + "addx %0,%2" + [(set_attr "type" "int2") + (set_attr "length" "2")]) + (define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "register_operand" "r")))] "" "sub %0,%2" - [(set_attr "type" "binary")]) + [(set_attr "type" "int2") + (set_attr "length" "2")]) (define_insn "subdi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -871,13 +874,51 @@ (match_operand:DI 2 "register_operand" "r"))) (clobber (reg:CC 17))] "" - "* -{ - /* ??? The cmp clears the condition bit. Can we speed up somehow? */ - return \"cmp %L0,%L0\;subx %L0,%L2\;subx %H0,%H2\"; -}" - [(set_attr "type" "binary") + "#" + [(set_attr "type" "multi") (set_attr "length" "6")]) + +;; ??? The cmp clears the condition bit. Can we speed up somehow? +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (match_operand 3 "" ""))] + "reload_completed" + [(parallel [(set (match_dup 3) + (const_int 0)) + (use (match_dup 4))]) + (parallel [(set (match_dup 4) + (minus:SI (match_dup 4) + (minus:SI (match_dup 5) + (match_dup 3)))) + (set (match_dup 3) + (unspec [(const_int 0)] 3))]) + (parallel [(set (match_dup 6) + (minus:SI (match_dup 6) + (minus:SI (match_dup 7) + (match_dup 3)))) + (set (match_dup 3) + (unspec [(const_int 0)] 3))])] + " +{ + operands[4] = operand_subword (operands[0], (WORDS_BIG_ENDIAN != 0), 0, DImode); + operands[5] = operand_subword (operands[2], (WORDS_BIG_ENDIAN != 0), 0, DImode); + operands[6] = operand_subword (operands[0], (WORDS_BIG_ENDIAN == 0), 0, DImode); + operands[7] = operand_subword (operands[2], (WORDS_BIG_ENDIAN == 0), 0, DImode); +}") + +(define_insn "*sub_carry" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "%0") + (minus:SI (match_operand:SI 2 "register_operand" "r") + (reg:CC 17)))) + (set (reg:CC 17) + (unspec [(const_int 0)] 3))] + "" + "subx %0,%2" + [(set_attr "type" "int2") + (set_attr "length" "2")]) ; Multiply/Divide instructions. @@ -887,7 +928,7 @@ (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] "" "mullo %1,%2\;mvfacmi %0" - [(set_attr "type" "mul") + [(set_attr "type" "multi") (set_attr "length" "4")]) (define_insn "mulsi3" @@ -896,7 +937,8 @@ (match_operand:SI 2 "register_operand" "r")))] "" "mul %0,%2" - [(set_attr "type" "mul")]) + [(set_attr "type" "mul2") + (set_attr "length" "2")]) (define_insn "divsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -904,7 +946,8 @@ (match_operand:SI 2 "register_operand" "r")))] "" "div %0,%2" - [(set_attr "type" "div")]) + [(set_attr "type" "div4") + (set_attr "length" "4")]) (define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -912,7 +955,8 @@ (match_operand:SI 2 "register_operand" "r")))] "" "divu %0,%2" - [(set_attr "type" "div")]) + [(set_attr "type" "div4") + (set_attr "length" "4")]) (define_insn "modsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -920,7 +964,8 @@ (match_operand:SI 2 "register_operand" "r")))] "" "rem %0,%2" - [(set_attr "type" "div")]) + [(set_attr "type" "div4") + (set_attr "length" "4")]) (define_insn "umodsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -928,7 +973,8 @@ (match_operand:SI 2 "register_operand" "r")))] "" "remu %0,%2" - [(set_attr "type" "div")]) + [(set_attr "type" "div4") + (set_attr "length" "4")]) ;; Boolean instructions. ;; @@ -942,8 +988,9 @@ "" "@ and %0,%2 - and3 %0,%1,%#%2 ; %X2" - [(set_attr "type" "binary")]) + and3 %0,%1,%#%2\\t; %X2" + [(set_attr "type" "int2,int4") + (set_attr "length" "2,4")]) (define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -952,8 +999,9 @@ "" "@ or %0,%2 - or3 %0,%1,%#%2 ; %X2" - [(set_attr "type" "binary")]) + or3 %0,%1,%#%2\\t; %X2" + [(set_attr "type" "int2,int4") + (set_attr "length" "2,4")]) (define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -962,22 +1010,25 @@ "" "@ xor %0,%2 - xor3 %0,%1,%#%2 ; %X2" - [(set_attr "type" "binary")]) + xor3 %0,%1,%#%2\\t; %X2" + [(set_attr "type" "int2,int4") + (set_attr "length" "2,4")]) (define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "register_operand" "r")))] "" "neg %0,%1" - [(set_attr "type" "unary")]) + [(set_attr "type" "int2") + (set_attr "length" "2")]) (define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_operand" "r")))] "" "not %0,%1" - [(set_attr "type" "unary")]) + [(set_attr "type" "int2") + (set_attr "length" "2")]) ;; Shift instructions. @@ -990,7 +1041,7 @@ sll %0,%2 slli %0,%#%2 sll3 %0,%1,%#%2" - [(set_attr "type" "shift") + [(set_attr "type" "shift2,shift2,shift4") (set_attr "length" "2,2,4")]) (define_insn "ashrsi3" @@ -1002,7 +1053,7 @@ sra %0,%2 srai %0,%#%2 sra3 %0,%1,%#%2" - [(set_attr "type" "shift") + [(set_attr "type" "shift2,shift2,shift4") (set_attr "length" "2,2,4")]) (define_insn "lshrsi3" @@ -1014,7 +1065,7 @@ srl %0,%2 srli %0,%#%2 srl3 %0,%1,%#%2" - [(set_attr "type" "shift") + [(set_attr "type" "shift2,shift2,shift4") (set_attr "length" "2,2,4")]) ;; Compare instructions. @@ -1067,7 +1118,7 @@ return \"add3 %2,%0,%#%N1\;cmpui %2,#1\"; } }" - [(set_attr "type" "compare,compare") + [(set_attr "type" "multi,multi") (set_attr "length" "8,8")]) (define_insn "cmp_ltsi_insn" @@ -1078,23 +1129,19 @@ "@ cmp %0,%1 cmpi %0,%#%1" - [(set_attr "type" "compare,compare") - (set_attr "length" "4,6")]) + [(set_attr "type" "int2,int4") + (set_attr "length" "2,4")]) (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")))] "" - "* -{ - if (which_alternative == 0) - return \"cmpu %0,%1\"; - else - return \"cmpui %0,%#%1\"; -}" - [(set_attr "type" "compare") - (set_attr "length" "4,6")]) + "@ + cmpu %0,%1 + cmpui %0,%#%1" + [(set_attr "type" "int2,int4") + (set_attr "length" "2,4")]) ;; reg == small constant comparisons are best handled by putting the result ;; of the comparison in a tmp reg and then using beqz/bnez. @@ -1104,12 +1151,12 @@ (define_insn "cmp_ne_small_const_insn" [(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")))] + (match_operand:SI 2 "cmp_int16_operand" "N,P")))] "" "@ addi %0,%#%N2 add3 %0,%1,%#%N2" - [(set_attr "type" "compare") + [(set_attr "type" "int2,int4") (set_attr "length" "2,4")]) ;; These control RTL generation for conditional jump insns. @@ -1582,7 +1629,7 @@ [(const_int 0)] "" "nop" - [(set_attr "type" "misc") + [(set_attr "type" "int2") (set_attr "length" "2")]) ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and @@ -1599,7 +1646,8 @@ [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 0)] "" "* return \"nop ; flush-icache\";" - [(set_attr "type" "misc")]) + [(set_attr "type" "int2") + (set_attr "length" "2")]) ;; Conditional move instructions ;; Based on those done for the d10v @@ -1638,7 +1686,7 @@ )] "zero_and_one (operands [2], operands[3])" "* return emit_cond_move (operands, insn);" - [(set_attr "type" "move") + [(set_attr "type" "multi") (set_attr "length" "8") ] ) @@ -1657,9 +1705,9 @@ [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r") (const_int 4))) (match_operand:SI 1 "register_operand" "r"))] - "dead_or_set_p (insn, operands[0])" + "0 && dead_or_set_p (insn, operands[0])" "st %1,@+%0" - [(set_attr "type" "store") + [(set_attr "type" "store2") (set_attr "length" "2")]) ;; This case is triggered by compiling this code: @@ -1698,9 +1746,9 @@ (match_dup 0) ) ] - "dead_or_set_p (insn, operands [0])" + "0 && dead_or_set_p (insn, operands [0])" "st %1,@(%3,%2)" - [(set_attr "type" "store") + [(set_attr "type" "store4") (set_attr "length" "4") ] ) |