diff options
author | nickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-05-09 11:44:58 +0000 |
---|---|---|
committer | nickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-05-09 11:44:58 +0000 |
commit | dce5e16b91b76f56c94b1777685f5704495c5b5a (patch) | |
tree | 4a83a2d6833b91c14aa8edc0efbc99d40e6145af /gcc/config/rl78/rl78.c | |
parent | 189d070677016c1ea25553a3ab4d926c6c20a434 (diff) | |
download | gcc-dce5e16b91b76f56c94b1777685f5704495c5b5a.tar.gz |
* config/rl78/rl78.c (rl78_expand_prologue): Save the MDUC related
registers in all interrupt handlers if necessary.
(rl78_option_override): Add warning.
(MUST_SAVE_MDUC_REGISTERS): New macro.
(rl78_expand_epilogue): Restore the MDUC registers if necessary.
* config/rl78/rl78.c (check_mduc_usage): New function.
(mduc_regs): New structure to hold MDUC register data.
* config/rl78/rl78.md (is_g13_muldiv_insn): New attribute.
(mulsi3_g13): Add is_g13_muldiv_insn attribute.
(udivmodsi4_g13): Add is_g13_muldiv_insn attribute.
(mulhi3_g13): Add is_g13_muldiv_insn attribute.
* config/rl78/rl78.opt (msave-mduc-in-interrupts): New option.
* doc/invoke.texi (RL78 Options): Add -msave-mduc-in-interrupts.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@236027 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rl78/rl78.c')
-rw-r--r-- | gcc/config/rl78/rl78.c | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c index 13c22539268..2d850610ea6 100644 --- a/gcc/config/rl78/rl78.c +++ b/gcc/config/rl78/rl78.c @@ -76,6 +76,23 @@ static const char * const word_regnames[] = "sp", "ap", "psw", "es", "cs" }; +/* Structure for G13 MDUC registers. */ +struct mduc_reg_type +{ + unsigned int address; + enum machine_mode mode; +}; + +struct mduc_reg_type mduc_regs[] = +{ + {0xf00e8, QImode}, + {0xffff0, HImode}, + {0xffff2, HImode}, + {0xf2224, HImode}, + {0xf00e0, HImode}, + {0xf00e2, HImode} +}; + struct GTY(()) machine_function { /* If set, the rest of the fields have been computed. */ @@ -317,6 +334,10 @@ rl78_output_symbol_ref (FILE * file, rtx sym) #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE rl78_option_override +#define MUST_SAVE_MDUC_REGISTERS \ + (TARGET_SAVE_MDUC_REGISTERS \ + && (is_interrupt_func (NULL_TREE)) && RL78_MUL_G13) + static void rl78_option_override (void) { @@ -344,6 +365,9 @@ rl78_option_override (void) /* Address spaces are currently only supported by C. */ error ("-mes0 can only be used with C"); + if (TARGET_SAVE_MDUC_REGISTERS && !(TARGET_G13 || RL78_MUL_G13)) + warning (0, "mduc registers only saved for G13 target"); + switch (rl78_cpu_type) { case CPU_UNINIT: @@ -1257,13 +1281,34 @@ rl78_initial_elimination_offset (int from, int to) return rv; } -static int +static bool rl78_is_naked_func (void) { return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE); } +/* Check if the block uses mul/div insns for G13 target. */ + +static bool +check_mduc_usage (void) +{ + rtx_insn * insn; + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (INSN_P (insn) + && (get_attr_is_g13_muldiv_insn (insn) == IS_G13_MULDIV_INSN_YES)) + return true; + } + } + return false; +} + /* Expand the function prologue (from the prologue pattern). */ + void rl78_expand_prologue (void) { @@ -1278,6 +1323,9 @@ rl78_expand_prologue (void) /* Always re-compute the frame info - the register usage may have changed. */ rl78_compute_frame_info (); + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + cfun->machine->framesize += ARRAY_SIZE (mduc_regs) * 2; + if (flag_stack_usage_info) current_function_static_stack_size = cfun->machine->framesize; @@ -1327,6 +1375,24 @@ rl78_expand_prologue (void) F (emit_insn (gen_push (ax))); } + /* Save MDUC registers inside interrupt routine. */ + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + { + for (int i = 0; i < ARRAY_SIZE (mduc_regs); i++) + { + mduc_reg_type *reg = mduc_regs + i; + rtx mem_mduc = gen_rtx_MEM (reg->mode, GEN_INT (reg->address)); + + MEM_VOLATILE_P (mem_mduc) = 1; + if (reg->mode == QImode) + emit_insn (gen_movqi (gen_rtx_REG (QImode, A_REG), mem_mduc)); + else + emit_insn (gen_movhi (gen_rtx_REG (HImode, AX_REG), mem_mduc)); + + emit_insn (gen_push (gen_rtx_REG (HImode, AX_REG))); + } + } + if (frame_pointer_needed) { F (emit_move_insn (ax, sp)); @@ -1400,6 +1466,23 @@ rl78_expand_epilogue (void) } } + /* Restore MDUC registers from interrupt routine. */ + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + { + for (int i = ARRAY_SIZE (mduc_regs) - 1; i >= 0; i--) + { + mduc_reg_type *reg = mduc_regs + i; + rtx mem_mduc = gen_rtx_MEM (reg->mode, GEN_INT (reg->address)); + + emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG))); + MEM_VOLATILE_P (mem_mduc) = 1; + if (reg->mode == QImode) + emit_insn (gen_movqi (mem_mduc, gen_rtx_REG (QImode, A_REG))); + else + emit_insn (gen_movhi (mem_mduc, gen_rtx_REG (HImode, AX_REG))); + } + } + if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es) { emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG))); @@ -1495,6 +1578,9 @@ rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED) if (cfun->machine->uses_es) fprintf (file, "\t; uses ES register\n"); + + if (MUST_SAVE_MDUC_REGISTERS) + fprintf (file, "\t; preserves MDUC registers\n"); } /* Return an RTL describing where a function return value of type RET_TYPE |