Commit 5b8ae21f by Michael Meissner Committed by Michael Meissner

Hunk of m32r changes

From-SVN: r19636
parent cf879efa
......@@ -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
......
......@@ -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 :
......
......@@ -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));
......
......@@ -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")
]
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment