diff options
author | Richard Sandiford <r.sandiford@redhat.com> | 2000-12-06 03:56:43 +0000 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 2000-12-05 20:56:43 -0700 |
commit | f6cd7c62a1f5213c6f34ddc0067f426227310cdf (patch) | |
tree | abea5247ce4be47b3e7df3bbcaf8a24e8b2bfe46 | |
parent | 598730fe6e7b2da6bbc72a7a5a1cdd189381e9e7 (diff) | |
download | gcc-f6cd7c62a1f5213c6f34ddc0067f426227310cdf.zip gcc-f6cd7c62a1f5213c6f34ddc0067f426227310cdf.tar.gz gcc-f6cd7c62a1f5213c6f34ddc0067f426227310cdf.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300-protos.h | 4 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.c | 218 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.md | 100 |
4 files changed, 239 insertions, 97 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bc095849..69b5ecc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h index 66dcbe2..ee4a443 100644 --- a/gcc/config/mn10300/mn10300-protos.h +++ b/gcc/config/mn10300/mn10300-protos.h @@ -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)); diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 3a5454c..bc6b1fc 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -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 diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index cfa9c51..564a4c9 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -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 ()" |