Add movdi pattern to FR30 port.
From-SVN: r33885
This commit is contained in:
parent
1d11bf189e
commit
aeb4f5ef5d
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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: */
|
||||
|
@ -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 }},
|
||||
|
||||
/*}}}*/
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user