Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
{
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 :
return gen_rtx (branch_code, VOIDmode, cc_reg, CONST0_RTX (mode));
}
+\f
+/* 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;
+}
+
\f
/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */
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 */
&& (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 */
{
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;
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
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;
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;
if (! current_frame_info.initialized)
m32r_compute_frame_size (get_frame_size ());
- return current_frame_info.prolog_size;
+ return 0;
}
\f
-/* 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);
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 ());
+}
+
+\f
+/* 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);
}
\f
/* Do any necessary cleanup after a function to restore stack, frame,
rtx x;
int code;
{
+ rtx addr;
+
switch (code)
{
case 'R' :
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 :
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 :
#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.
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
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)
\f
/* Stack layout and stack pointer usage. */
/* 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 ()
\f
/* Trampolines. */
(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
/* 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)
\f
/* Condition code usage. */
/* 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. */
#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
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. */
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 *,
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));
;; 0 - blockage
;; 1 - flush_icache
;; 2 - load_sda_base
+;; 3 - setting carry in addx/subx instructions.
\f
;; 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)
;; 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)")))
;; (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")])
+
+
+\f
+;; Instruction grouping
\f
;; Expand prologue as RTL
-;; ??? Unfinished.
-
-;(define_expand "prologue"
-; [(const_int 1)]
-; ""
-; "
-;{
-;}")
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+ "
+{
+ m32r_expand_prologue ();
+ DONE;
+}")
+
\f
;; Move instructions.
;;
}")
(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" "")
}")
(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
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" "")
}
}")
-(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.
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
(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.
(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")
(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" "")
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);")
\f
;; Floating point move insns.
}")
(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" "")
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);")
\f
;; 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")])
\f
;; Sign extension instructions.
;; ??? See v850.md.
}")
(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" "")
}")
(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" "")
}")
(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")])
\f
;; Arithmetic instructions.
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
(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")
(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")])
\f
; Multiply/Divide instructions.
(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"
(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")
(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")
(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")
(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")
(match_operand:SI 2 "register_operand" "r")))]
""
"remu %0,%2"
- [(set_attr "type" "div")])
+ [(set_attr "type" "div4")
+ (set_attr "length" "4")])
\f
;; Boolean instructions.
;;
""
"@
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")
""
"@
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")
""
"@
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")])
\f
;; Shift instructions.
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"
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"
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")])
\f
;; Compare instructions.
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"
"@
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.
(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")])
\f
;; These control RTL generation for conditional jump insns.
[(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
[(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")])
\f
;; Conditional move instructions
;; Based on those done for the d10v
)]
"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")
]
)
[(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:
(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")
]
)