Index: gcc/config/rl78/rl78.c =================================================================== --- gcc/config/rl78/rl78.c (revision 2871) +++ gcc/config/rl78/rl78.c (working copy) @@ -83,6 +83,22 @@ "sp", "ap", "psw", "es", "cs" }; +/* Structure for G13 MDUC registers. */ +struct mduc_reg_type +{ + unsigned int address; + enum machine_mode mode; + bool is_volatile; +}; + +struct mduc_reg_type mduc_regs[NUM_OF_MDUC_REGS] = + {{0xf00e8, QImode, true}, + {0xffff0, HImode, true}, + {0xffff2, HImode, true}, + {0xf2224, HImode, true}, + {0xf00e0, HImode, true}, + {0xf00e2, HImode, true}}; + struct GTY(()) machine_function { /* If set, the rest of the fields have been computed. */ @@ -342,6 +358,10 @@ #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE rl78_option_override +#define MUST_SAVE_MDUC_REGISTERS \ + (!TARGET_NO_SAVE_MDUC_REGISTERS \ + && (is_interrupt_func (NULL_TREE)) && RL78_MUL_G13) + static void rl78_option_override (void) { @@ -366,6 +386,9 @@ /* 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: @@ -1307,6 +1330,23 @@ 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 () +{ + rtx insn; + basic_block bb; + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (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) @@ -1371,6 +1411,28 @@ F (emit_insn (gen_push (ax))); } + /* Save MDUC registers inside interrupt routine. */ + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + { + rtx mem_mduc; + + for (int i = 0; i machine->framesize_locals + cfun->machine->framesize_outgoing; + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + fs = fs + NUM_OF_MDUC_REGS * 2; if (fs > 0) { /* If we need to subtract more than 254*3 then it is faster and @@ -1426,6 +1490,8 @@ else { fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing; + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + fs = fs + NUM_OF_MDUC_REGS * 2; if (fs > 254 * 3) { emit_move_insn (ax, sp); @@ -1444,6 +1510,29 @@ } } + /* Restore MDUC registers from interrupt routine. */ + if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ())) + { + rtx mem_mduc; + + for (int i = NUM_OF_MDUC_REGS-1; i >= 0; i--) + { + emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG))); + if (mduc_regs[i].mode == QImode) + { + mem_mduc = gen_rtx_MEM (QImode, GEN_INT (mduc_regs[i].address)); + MEM_VOLATILE_P (mem_mduc) = 1; + emit_insn (gen_movqi (mem_mduc, gen_rtx_REG (QImode, A_REG))); + } + else + { + mem_mduc = gen_rtx_MEM (HImode, GEN_INT (mduc_regs[i].address)); + MEM_VOLATILE_P (mem_mduc) = 1; + emit_insn (gen_movhi (mem_mduc, gen_rtx_REG (HImode, AX_REG))); + } + } + } + /* Save ES register inside interrupt functions. */ if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es) { @@ -1599,6 +1688,9 @@ 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 Index: gcc/config/rl78/rl78.h =================================================================== --- gcc/config/rl78/rl78.h (revision 2871) +++ gcc/config/rl78/rl78.h (working copy) @@ -28,6 +28,7 @@ #define TARGET_G14 (rl78_cpu_type == CPU_G14) +#define NUM_OF_MDUC_REGS 6 #define TARGET_CPU_CPP_BUILTINS() \ do \ Index: gcc/config/rl78/rl78.md =================================================================== --- gcc/config/rl78/rl78.md (revision 2871) +++ gcc/config/rl78/rl78.md (working copy) @@ -78,6 +78,7 @@ (include "rl78-virt.md") (include "rl78-real.md") +(define_attr "is_g13_muldiv_insn" "yes,no" (const_string "no")) ;; Function Prologue/Epilogue Instructions @@ -416,7 +417,8 @@ movw ax, 0xffff6 ; MDBL movw %h0, ax ; end of mulhi macro" - [(set_attr "valloc" "macax")] + [(set_attr "valloc" "macax") + (set_attr "is_g13_muldiv_insn" "yes")] ) ;; 0xFFFF0 is MACR(L). 0xFFFF2 is MACR(H) but we don't care about it @@ -496,7 +498,8 @@ movw ax, !0xf00e0 ; MDCL movw %H0, ax ; end of mulsi macro" - [(set_attr "valloc" "macax")] + [(set_attr "valloc" "macax") + (set_attr "is_g13_muldiv_insn" "yes")] ) ;; start-sanitize-rl78 @@ -731,7 +734,8 @@ movw %H3, ax \n\ ; end of udivmodsi macro"; } - [(set_attr "valloc" "macax")] + [(set_attr "valloc" "macax") + (set_attr "is_g13_muldiv_insn" "yes")] ) (define_insn "mov1" [(set (match_operand:QI 0 "rl78_nonimmediate_operand" "=vU") Index: gcc/config/rl78/rl78.opt =================================================================== --- gcc/config/rl78/rl78.opt (revision 2871) +++ gcc/config/rl78/rl78.opt (working copy) @@ -103,4 +103,10 @@ Target Mask(ES0) Assume ES is zero throughout program execution, use ES: for read-only data. +msave-mduc-in-interrupts +Target Mask(SAVE_MDUC_REGISTERS) +Stores the MDUC registers in interrupt handlers for G13 target. +mno-save-mduc-in-interrupts +Target RejectNegative Mask(NO_SAVE_MDUC_REGISTERS) +Does not save the MDUC registers in interrupt handlers for G13 target. Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 2871) +++ gcc/doc/invoke.texi (working copy) @@ -18901,6 +18901,20 @@ registers @code{r24..r31} are reserved for use in interrupt handlers. With this option enabled these registers can be used in ordinary functions as well. + +@item -msave-mduc-in-interrupts +@item -mno-save-mduc-in-interrupts +@opindex msave-mduc-in-interrupts +@opindex mno-save-mduc-in-interrupts +Specifies that interrupt handler functions should preserve the +MDUC registers. This is only necessary if normal code might use +the MDUC registers, for example because it performs multiplication +and division operations. The default is to ignore the MDUC registers +as this makes the interrupt handlers faster. The target option -mg13 +needs to be passed for this to work as this feature is only available +on the G13 target (S2 core). The option will not have any effect if +the target does not have multiply hardware, or if the interrupt +function does not call any other function. @end table @node RS/6000 and PowerPC Options