mn10300.c (mn10300_print_reg_list): Added.
2000-12-05 Richard Sandiford <r.sandiford@redhat.com> * config/mn10300/mn10300.c (mn10300_print_reg_list): Added. (mn10300_get_live_callee_saved_regs): Likewise. (mn10300_gen_multiple_store): Likewise. (store_multiple_operation): Likewise. (expand_prologue): Use mn10300_gen_multiple_store(). * config/mn10300/mn10300-protos.h (mn10300_print_reg_list): Added. (mn10300_get_live_callee_saved_regs): Likewise. (mn10300_gen_multiple_store): Likewise. (store_multiple_operation): Likewise. * config/mn10300/mn10300.md (store_movm): Use a MATCH_PARALLEL tied to store_multiple_operation(). From-SVN: r38062
This commit is contained in:
parent
598730fe6e
commit
f6cd7c62a1
4 changed files with 239 additions and 97 deletions
|
@ -1,3 +1,17 @@
|
|||
2000-12-05 Richard Sandiford <r.sandiford@redhat.com>
|
||||
|
||||
* config/mn10300/mn10300.c (mn10300_print_reg_list): Added.
|
||||
(mn10300_get_live_callee_saved_regs): Likewise.
|
||||
(mn10300_gen_multiple_store): Likewise.
|
||||
(store_multiple_operation): Likewise.
|
||||
(expand_prologue): Use mn10300_gen_multiple_store().
|
||||
* config/mn10300/mn10300-protos.h (mn10300_print_reg_list): Added.
|
||||
(mn10300_get_live_callee_saved_regs): Likewise.
|
||||
(mn10300_gen_multiple_store): Likewise.
|
||||
(store_multiple_operation): Likewise.
|
||||
* config/mn10300/mn10300.md (store_movm): Use a MATCH_PARALLEL
|
||||
tied to store_multiple_operation().
|
||||
|
||||
Tue Dec 5 20:09:14 2000 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* builtins.c (expand_builtin_setjmp_setup): Set
|
||||
|
|
|
@ -28,10 +28,14 @@ extern void mn10300_va_start PARAMS ((int, tree, rtx));
|
|||
extern struct rtx_def *legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
|
||||
extern void print_operand PARAMS ((FILE *, rtx, int));
|
||||
extern void print_operand_address PARAMS ((FILE *, rtx));
|
||||
extern void mn10300_print_reg_list PARAMS ((FILE *, int));
|
||||
extern int mn10300_get_live_callee_saved_regs PARAMS ((void));
|
||||
extern void mn10300_gen_multiple_store PARAMS ((int));
|
||||
extern void notice_update_cc PARAMS ((rtx, rtx));
|
||||
extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
|
||||
enum machine_mode, rtx));
|
||||
extern char *output_tst PARAMS ((rtx, rtx));
|
||||
extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
|
||||
extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
|
||||
extern int call_address_operand PARAMS ((rtx, enum machine_mode));
|
||||
extern int impossible_plus_operand PARAMS ((rtx, enum machine_mode));
|
||||
|
|
|
@ -361,6 +361,45 @@ print_operand_address (file, addr)
|
|||
}
|
||||
}
|
||||
|
||||
/* Print a set of registers in the format required by "movm" and "ret".
|
||||
Register K is saved if bit K of MASK is set. The data and address
|
||||
registers can be stored individually, but the extended registers cannot.
|
||||
We assume that the mask alread takes that into account. For instance,
|
||||
bits 14 to 17 must have the same value. */
|
||||
|
||||
void
|
||||
mn10300_print_reg_list (file, mask)
|
||||
FILE *file;
|
||||
int mask;
|
||||
{
|
||||
int need_comma;
|
||||
int i;
|
||||
|
||||
need_comma = 0;
|
||||
fputc ('[', file);
|
||||
|
||||
for (i = 0; i < FIRST_EXTENDED_REGNUM; i++)
|
||||
if ((mask & (1 << i)) != 0)
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', file);
|
||||
fputs (reg_names [i], file);
|
||||
need_comma = 1;
|
||||
}
|
||||
|
||||
if ((mask & 0x3c000) != 0)
|
||||
{
|
||||
if ((mask & 0x3c000) != 0x3c000)
|
||||
abort();
|
||||
if (need_comma)
|
||||
fputc (',', file);
|
||||
fputs ("exreg1", file);
|
||||
need_comma = 1;
|
||||
}
|
||||
|
||||
fputc (']', file);
|
||||
}
|
||||
|
||||
int
|
||||
can_use_return_insn ()
|
||||
{
|
||||
|
@ -383,6 +422,94 @@ can_use_return_insn ()
|
|||
&& !frame_pointer_needed);
|
||||
}
|
||||
|
||||
/* Returns the set of live, callee-saved registers as a bitmask. The
|
||||
callee-saved extended registers cannot be stored individually, so
|
||||
all of them will be included in the mask if any one of them is used. */
|
||||
|
||||
int
|
||||
mn10300_get_live_callee_saved_regs ()
|
||||
{
|
||||
int mask;
|
||||
int i;
|
||||
|
||||
mask = 0;
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (regs_ever_live[i] && ! call_used_regs[i])
|
||||
mask |= (1 << i);
|
||||
if ((mask & 0x3c000) != 0)
|
||||
mask |= 0x3c000;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Generate an instruction that pushes several registers onto the stack.
|
||||
Register K will be saved if bit K in MASK is set. The function does
|
||||
nothing if MASK is zero.
|
||||
|
||||
To be compatible with the "movm" instruction, the lowest-numbered
|
||||
register must be stored in the lowest slot. If MASK is the set
|
||||
{ R1,...,RN }, where R1...RN are ordered least first, the generated
|
||||
instruction will have the form:
|
||||
|
||||
(parallel
|
||||
(set (reg:SI 9) (plus:SI (reg:SI 9) (const_int -N*4)))
|
||||
(set (mem:SI (plus:SI (reg:SI 9)
|
||||
(const_int -1*4)))
|
||||
(reg:SI RN))
|
||||
...
|
||||
(set (mem:SI (plus:SI (reg:SI 9)
|
||||
(const_int -N*4)))
|
||||
(reg:SI R1))) */
|
||||
|
||||
void
|
||||
mn10300_gen_multiple_store (mask)
|
||||
int mask;
|
||||
{
|
||||
if (mask != 0)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
rtx par;
|
||||
int pari;
|
||||
|
||||
/* Count how many registers need to be saved. */
|
||||
count = 0;
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if ((mask & (1 << i)) != 0)
|
||||
count += 1;
|
||||
|
||||
/* We need one PARALLEL element to update the stack pointer and
|
||||
an additional element for each register that is stored. */
|
||||
par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
|
||||
|
||||
/* Create the instruction that updates the stack pointer. */
|
||||
XVECEXP (par, 0, 0)
|
||||
= gen_rtx_SET (SImode,
|
||||
stack_pointer_rtx,
|
||||
gen_rtx_PLUS (SImode,
|
||||
stack_pointer_rtx,
|
||||
GEN_INT (-count * 4)));
|
||||
|
||||
/* Create each store. */
|
||||
pari = 1;
|
||||
for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
|
||||
if ((mask & (1 << i)) != 0)
|
||||
{
|
||||
rtx address = gen_rtx_PLUS (SImode,
|
||||
stack_pointer_rtx,
|
||||
GEN_INT (-pari * 4));
|
||||
XVECEXP(par, 0, pari)
|
||||
= gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (SImode, address),
|
||||
gen_rtx_REG (SImode, i));
|
||||
pari += 1;
|
||||
}
|
||||
|
||||
par = emit_insn (par);
|
||||
RTX_FRAME_RELATED_P (par) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
expand_prologue ()
|
||||
{
|
||||
|
@ -404,14 +531,8 @@ expand_prologue ()
|
|||
gen_rtx_REG (SImode, 1));
|
||||
}
|
||||
|
||||
/* And now store all the registers onto the stack with a
|
||||
single two byte instruction. */
|
||||
if (regs_ever_live[2] || regs_ever_live[3]
|
||||
|| regs_ever_live[6] || regs_ever_live[7]
|
||||
|| regs_ever_live[14] || regs_ever_live[15]
|
||||
|| regs_ever_live[16] || regs_ever_live[17]
|
||||
|| frame_pointer_needed)
|
||||
emit_insn (gen_store_movm ());
|
||||
/* If we use any of the callee-saved registers, save them now. */
|
||||
mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
|
||||
|
||||
/* Now put the frame pointer into the frame pointer register. */
|
||||
if (frame_pointer_needed)
|
||||
|
@ -532,6 +653,87 @@ notice_update_cc (body, insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* Recognise the PARALLEL rtx generated by mn10300_gen_multiple_store().
|
||||
This function is for MATCH_PARALLEL and so assumes OP is known to be
|
||||
parallel. If OP is a multiple store, return a mask indicating which
|
||||
registers it saves. Return 0 otherwise. */
|
||||
|
||||
int
|
||||
store_multiple_operation (op, mode)
|
||||
rtx op;
|
||||
enum machine_mode mode ATTRIBUTE_UNUSED;
|
||||
{
|
||||
int count;
|
||||
int mask;
|
||||
int i;
|
||||
unsigned int last;
|
||||
rtx elt;
|
||||
|
||||
count = XVECLEN (op, 0);
|
||||
if (count < 2)
|
||||
return 0;
|
||||
|
||||
/* Check that first instruction has the form (set (sp) (plus A B)) */
|
||||
elt = XVECEXP (op, 0, 0);
|
||||
if (GET_CODE (elt) != SET
|
||||
|| GET_CODE (SET_DEST (elt)) != REG
|
||||
|| REGNO (SET_DEST (elt)) != STACK_POINTER_REGNUM
|
||||
|| GET_CODE (SET_SRC (elt)) != PLUS)
|
||||
return 0;
|
||||
|
||||
/* Check that A is the stack pointer and B is the expected stack size.
|
||||
For OP to match, each subsequent instruction should push a word onto
|
||||
the stack. We therefore expect the first instruction to create
|
||||
COUNT-1 stack slots. */
|
||||
elt = SET_SRC (elt);
|
||||
if (GET_CODE (XEXP (elt, 0)) != REG
|
||||
|| REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
|
||||
|| GET_CODE (XEXP (elt, 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (elt, 1)) != -(count - 1) * 4)
|
||||
return 0;
|
||||
|
||||
/* Now go through the rest of the vector elements. They must be
|
||||
ordered so that the first instruction stores the highest-numbered
|
||||
register to the highest stack slot and that subsequent instructions
|
||||
store a lower-numbered register to the slot below.
|
||||
|
||||
LAST keeps track of the smallest-numbered register stored so far.
|
||||
MASK is the set of stored registers. */
|
||||
last = FIRST_PSEUDO_REGISTER;
|
||||
mask = 0;
|
||||
for (i = 1; i < count; i++)
|
||||
{
|
||||
/* Check that element i is a (set (mem M) R) and that R is valid. */
|
||||
elt = XVECEXP (op, 0, i);
|
||||
if (GET_CODE (elt) != SET
|
||||
|| GET_CODE (SET_DEST (elt)) != MEM
|
||||
|| GET_CODE (SET_SRC (elt)) != REG
|
||||
|| REGNO (SET_SRC (elt)) >= last)
|
||||
return 0;
|
||||
|
||||
/* R was OK, so provisionally add it to MASK. We return 0 in any
|
||||
case if the rest of the instruction has a flaw. */
|
||||
last = REGNO (SET_SRC (elt));
|
||||
mask |= (1 << last);
|
||||
|
||||
/* Check that M has the form (plus (sp) (const_int -I*4)) */
|
||||
elt = XEXP (SET_DEST (elt), 0);
|
||||
if (GET_CODE (elt) != PLUS
|
||||
|| GET_CODE (XEXP (elt, 0)) != REG
|
||||
|| REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
|
||||
|| GET_CODE (XEXP (elt, 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (elt, 1)) != -i * 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* All or none of the callee-saved extended registers must be in the set. */
|
||||
if ((mask & 0x3c000) != 0
|
||||
&& (mask & 0x3c000) != 0x3c000)
|
||||
return 0;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Return true if OP is a valid call operand. */
|
||||
|
||||
int
|
||||
|
|
|
@ -1996,106 +1996,28 @@
|
|||
""
|
||||
"*
|
||||
{
|
||||
int need_comma;
|
||||
|
||||
need_comma = 0;
|
||||
fputs (\"\\tret [\", asm_out_file);
|
||||
if (regs_ever_live[2])
|
||||
{
|
||||
fputs (\"d2\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[3])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"d3\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[6])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"a2\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[7])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"a3\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[14] || regs_ever_live[15]
|
||||
|| regs_ever_live[16] || regs_ever_live[17])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"exreg1\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
fprintf (asm_out_file, \"],%d\\n\", INTVAL (operands[0]));
|
||||
fputs (\"\\tret \", asm_out_file);
|
||||
mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
|
||||
fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
|
||||
return \"\";
|
||||
}"
|
||||
[(set_attr "cc" "clobber")])
|
||||
|
||||
;; This instruction matches one generated by mn10300_gen_multiple_store()
|
||||
(define_insn "store_movm"
|
||||
[(const_int 1)
|
||||
(use (reg:SI 2))
|
||||
(use (reg:SI 3))
|
||||
(use (reg:SI 6))
|
||||
(use (reg:SI 7))
|
||||
(use (reg:SI 14))
|
||||
(use (reg:SI 15))
|
||||
(use (reg:SI 16))
|
||||
(use (reg:SI 17))
|
||||
(clobber (reg:SI 9))]
|
||||
[(match_parallel 0 "store_multiple_operation"
|
||||
[(set (reg:SI 9) (plus:SI (reg:SI 9) (match_operand 1 "" "")))])]
|
||||
""
|
||||
"*
|
||||
{
|
||||
int need_comma;
|
||||
|
||||
need_comma = 0;
|
||||
fputs (\"\\tmovm [\", asm_out_file);
|
||||
if (regs_ever_live[2])
|
||||
{
|
||||
fputs (\"d2\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[3])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"d3\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[6])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"a2\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[7])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"a3\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
if (regs_ever_live[14] || regs_ever_live[15]
|
||||
|| regs_ever_live[16] || regs_ever_live[17])
|
||||
{
|
||||
if (need_comma)
|
||||
fputc (',', asm_out_file);
|
||||
fputs (\"exreg1\", asm_out_file);
|
||||
need_comma = 1;
|
||||
}
|
||||
fputs (\"],(sp)\\n\", asm_out_file);
|
||||
fputs (\"\\tmovm \", asm_out_file);
|
||||
mn10300_print_reg_list (asm_out_file,
|
||||
store_multiple_operation (operands[0], VOIDmode));
|
||||
fprintf (asm_out_file, \",(sp)\\n\");
|
||||
return \"\";
|
||||
}"
|
||||
[(set_attr "cc" "clobber")])
|
||||
|
||||
|
||||
(define_insn "return"
|
||||
[(return)]
|
||||
"can_use_return_insn ()"
|
||||
|
|
Loading…
Add table
Reference in a new issue