Add movdi pattern to FR30 port.

From-SVN: r33885
This commit is contained in:
Nick Clifton 2000-05-12 20:57:57 +00:00 committed by Nick Clifton
parent 1d11bf189e
commit aeb4f5ef5d
5 changed files with 262 additions and 13 deletions

View File

@ -1,3 +1,22 @@
2000-05-12 Nick Clifton <nickc@cygnus.com>
* config/fr30/fr30.c (fr30_move_double): New function: Emit code
to move a double word value.
(di_operand): New function: Return true if the operand is suitbale
for a double word move operation.
(nonimmediate_di_operand): New function: Return true if the
operand is a DImode register or MEM.
* config/fr30/fr30.h (PREDICATE_CODES): Add di_operand and
nonimmediate_di_operand.
* config/fr30/fr30-protos.h Add fr30_move_double, di_operand, and
nonimmediate_di_operand.
* config/fr30/fr30.md (movdi): New pattern. Required because
other patterns generate DImode results.
(movdi_insn): New pattern.
2000-05-12 Richard Henderson <rth@cygnus.com>
* config/alpha/alpha.c (struct shadow_summary): Define

View File

@ -26,6 +26,7 @@ extern unsigned int fr30_compute_frame_size PARAMS ((int, int));
extern int fr30_check_multiple_regs PARAMS ((rtx *, int, int));
extern void fr30_print_operand PARAMS ((FILE *, rtx, int));
extern void fr30_print_operand_address PARAMS ((FILE *, rtx));
extern rtx fr30_move_double PARAMS ((rtx *));
#ifdef TREE_CODE
extern rtx fr30_va_arg PARAMS ((tree, tree));
#endif /* TREE_CODE */
@ -36,6 +37,8 @@ extern int add_immediate_operand PARAMS ((rtx, Mmode));
extern int high_register_operand PARAMS ((rtx, Mmode));
extern int low_register_operand PARAMS ((rtx, Mmode));
extern int call_operand PARAMS ((rtx, Mmode));
extern int di_operand PARAMS ((rtx, Mmode));
extern int nonimmediate_di_operand PARAMS ((rtx, Mmode));
#undef Mmode
#endif /* HAVE_MACHINE_MODES */
#endif /* RTX_CODE */

View File

@ -24,10 +24,8 @@ Boston, MA 02111-1307, USA. */
/*}}}*/
/*{{{ Includes */
#include <stdio.h>
#include <ctype.h>
#include <sys/param.h> /* so that MIn and MAX are defined before machmode.h */
#include "config.h"
#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
@ -44,7 +42,7 @@ Boston, MA 02111-1307, USA. */
#include "obstack.h"
#include "except.h"
#include "function.h"
#include "fr30-protos.h"
#include "tm_p.h"
/*}}}*/
/*{{{ Function Prologues & Epilogues */
@ -839,8 +837,7 @@ low_register_operand (operand, mode)
{
return
(GET_CODE (operand) == REG
&& REGNO (operand) <= 7
&& REGNO (operand) >= 0);
&& REGNO (operand) <= 7);
}
/* Returns true if OPERAND is suitable for use in a CALL insn. */
@ -854,6 +851,56 @@ call_operand (operand, mode)
|| GET_CODE (XEXP (operand, 0)) == REG));
}
/* Returns TRUE if OP is a valid operand of a DImode operation. */
int
di_operand (op, mode)
rtx op;
Mmode mode;
{
if (register_operand (op, mode))
return TRUE;
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
return FALSE;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
switch (GET_CODE (op))
{
case CONST_DOUBLE:
case CONST_INT:
return TRUE;
case MEM:
return memory_address_p (DImode, XEXP (op, 0));
default:
return FALSE;
}
}
/* Returns TRUE if OP is a DImode register or MEM. */
int
nonimmediate_di_operand (op, mode)
rtx op;
Mmode mode;
{
if (register_operand (op, mode))
return TRUE;
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
return FALSE;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) == MEM)
return memory_address_p (DImode, XEXP (op, 0));
return FALSE;
}
/* Returns true iff all the registers in the operands array
are in descending or ascending order. */
int
@ -864,9 +911,9 @@ fr30_check_multiple_regs (operands, num_operands, descending)
{
if (descending)
{
int prev_regno = -1;
unsigned int prev_regno = 0;
while (num_operands--)
while (num_operands --)
{
if (GET_CODE (operands [num_operands]) != REG)
return 0;
@ -879,9 +926,9 @@ fr30_check_multiple_regs (operands, num_operands, descending)
}
else
{
int prev_regno = CONDITION_CODE_REGNUM;
unsigned int prev_regno = CONDITION_CODE_REGNUM;
while (num_operands--)
while (num_operands --)
{
if (GET_CODE (operands [num_operands]) != REG)
return 0;
@ -896,6 +943,146 @@ fr30_check_multiple_regs (operands, num_operands, descending)
return 1;
}
/*}}}*/
/*{{{ Instruction Output Routines */
/* Output a double word move.
It must be REG<-REG, REG<-MEM, MEM<-REG or REG<-CONST.
On the FR30 we are contrained by the fact that it does not
support offsetable addresses, and so we have to load the
address of the secnd word into the second destination register
before we can use it. */
rtx
fr30_move_double (operands)
rtx * operands;
{
rtx src = operands[1];
rtx dest = operands[0];
enum rtx_code src_code = GET_CODE (src);
enum rtx_code dest_code = GET_CODE (dest);
enum machine_mode mode = GET_MODE (dest);
rtx val;
start_sequence ();
if (dest_code == REG)
{
if (src_code == REG)
{
int reverse = (REGNO (dest) == REGNO (src) + 1);
/* We normally copy the low-numbered register first. However, if
the first register of operand 0 is the same as the second register
of operand 1, we must copy in the opposite order. */
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)));
}
else if (src_code == MEM)
{
rtx addr = XEXP (src, 0);
int dregno = REGNO (dest);
rtx dest0;
rtx dest1;
rtx new_mem;
/* If the high-address word is used in the address, we
must load it last. Otherwise, load it first. */
int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0);
if (GET_CODE (addr) != REG)
abort ();
dest0 = operand_subword (dest, reverse, TRUE, mode);
dest1 = operand_subword (dest, !reverse, TRUE, mode);
if (reverse)
{
emit_insn (gen_rtx_SET (VOIDmode, dest1, change_address (src, SImode, addr)));
emit_insn (gen_rtx_SET (SImode, dest0, gen_rtx_REG (SImode, REGNO (addr))));
emit_insn (gen_rtx_SET (SImode, dest0, plus_constant (dest0, UNITS_PER_WORD)));
new_mem = gen_rtx_MEM (SImode, dest0);
MEM_COPY_ATTRIBUTES (new_mem, src);
emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem));
}
else
{
emit_insn (gen_rtx_SET (VOIDmode, dest0, change_address (src, SImode, addr)));
emit_insn (gen_rtx_SET (SImode, dest1, gen_rtx_REG (SImode, REGNO (addr))));
emit_insn (gen_rtx_SET (SImode, dest1, plus_constant (dest1, UNITS_PER_WORD)));
new_mem = gen_rtx_MEM (SImode, dest1);
MEM_COPY_ATTRIBUTES (new_mem, src);
emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
}
}
else if (src_code == CONST_INT || src_code == 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]));
}
}
else if (src_code == REG && dest_code == MEM)
{
rtx addr = XEXP (dest, 0);
rtx src0;
rtx src1;
if (GET_CODE (addr) != REG)
abort ();
src0 = operand_subword (src, 0, TRUE, mode);
src1 = operand_subword (src, 1, TRUE, mode);
emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, addr), src0));
if (REGNO (addr) == STACK_POINTER_REGNUM)
emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (stack_pointer_rtx, UNITS_PER_WORD)), src1));
else if (REGNO (addr) == FRAME_POINTER_REGNUM)
emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (frame_pointer_rtx, UNITS_PER_WORD)), src1));
else
{
rtx new_mem;
/* We need a scratch register to hold the value of 'address + 4'.
We ought to allow gcc to find one for us, but for now, just
push one of the source registers. */
emit_insn (gen_movsi_push (src0));
emit_insn (gen_movsi_internal (src0, addr));
emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD)));
new_mem = gen_rtx_MEM (SImode, src0);
MEM_COPY_ATTRIBUTES (new_mem, dest);
emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1));
emit_insn (gen_movsi_pop (src0));
}
}
else
/* This should have been prevented by the contraints on movdi_insn. */
abort ();
val = gen_sequence ();
end_sequence ();
return val;
}
/*}}}*/
/* Local Variables: */

View File

@ -84,7 +84,7 @@ extern int target_flags;
{ "small-model", TARGET_SMALL_MODEL_MASK, "Assume small address space" }, \
{ "no-small-model", - TARGET_SMALL_MODEL_MASK, "" }, \
{ "no-lsim", 0, "" }, \
{ "", TARGET_DEFAULT } \
{ "", TARGET_DEFAULT, "" } \
}
#define TARGET_VERSION fprintf (stderr, " (fr30)");
@ -889,9 +889,10 @@ enum reg_class
into the stack)
- if the type is a structure or union. */
#define MUST_PASS_IN_STACK(MODE,TYPE) \
#define MUST_PASS_IN_STACK(MODE, TYPE) \
(((MODE) == BLKmode) \
|| ((TYPE) != 0 \
|| ((TYPE) != NULL \
&& TYPE_SIZE (TYPE) != NULL \
&& (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
|| TREE_CODE (TYPE) == RECORD_TYPE \
|| TREE_CODE (TYPE) == UNION_TYPE \
@ -1763,6 +1764,8 @@ extern struct rtx_def * fr30_compare_op1;
{ "call_operand", { MEM }}, \
{ "fp_displacement_operand", { CONST_INT }}, \
{ "sp_displacement_operand", { CONST_INT }}, \
{ "di_operand", { CONST_INT, CONST_DOUBLE, REG, MEM }}, \
{ "nonimmediate_di_operand", { REG, MEM }}, \
{ "add_immediate_operand", { REG, CONST_INT }},
/*}}}*/

View File

@ -367,6 +367,43 @@
(const_int 2)))]
)
;;}}}
;;{{{ 8 Byte Moves
;; Note - the FR30 does not have an 8 byte load/store instruction
;; but we have to support this pattern because some other patterns
;; (eg muldisi2) can produce a DImode result.
;; (This code is stolen from the M32R port.)
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
"
/* Everything except mem = const or mem = mem can be done easily. */
if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (DImode, operands[1]);
")
;; We use an insn and a split so that we can generate
;; RTL rather than text from fr30_move_double().
(define_insn "*movdi_insn"
[(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,m,r")
(match_operand:DI 1 "di_operand" "r,m,r,nF"))]
"register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"
"#"
[(set_attr "length" "4,8,12,12")]
)
(define_split
[(set (match_operand:DI 0 "nonimmediate_di_operand" "")
(match_operand:DI 1 "di_operand" ""))]
"reload_completed"
[(match_dup 2)]
"operands[2] = fr30_move_double (operands);")
;;}}}
;;{{{ Load & Store Multiple Registers