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:
Richard Sandiford 2000-12-06 03:56:43 +00:00 committed by Jeff Law
parent 598730fe6e
commit f6cd7c62a1
4 changed files with 239 additions and 97 deletions

View file

@ -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

View file

@ -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));

View file

@ -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

View file

@ -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 ()"