+2016-05-09 Kaushik Phatak <kaushik.phatak@kpit.com>
+
+ * 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.
+
2016-05-09 Bin Cheng <bin.cheng@arm.com>
* tree-if-conv.c (tree-ssa-loop.h): Include header file.
"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. */
#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)
{
/* 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:
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)
{
/* 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;
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));
}
}
+ /* 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)));
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
(include "rl78-virt.md")
(include "rl78-real.md")
+(define_attr "is_g13_muldiv_insn" "yes,no" (const_string "no"))
;; Function Prologue/Epilogue Instructions
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
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")]
)
(define_expand "udivmodhi4"
movw %H3, ax \n\
; end of udivmodsi macro";
}
- [(set_attr "valloc" "macax")]
+ [(set_attr "valloc" "macax")
+ (set_attr "is_g13_muldiv_insn" "yes")]
)
@emph{RL78 Options}
@gccoptlist{-msim -mmul=none -mmul=g13 -mmul=g14 -mallregs @gol
-mcpu=g10 -mcpu=g13 -mcpu=g14 -mg10 -mg13 -mg14 @gol
--m64bit-doubles -m32bit-doubles}
+-m64bit-doubles -m32bit-doubles -msave-mduc-in-interrupts}
@emph{RS/6000 and PowerPC Options}
@gccoptlist{-mcpu=@var{cpu-type} @gol
or 32 bits (@option{-m32bit-doubles}) in size. The default is
@option{-m32bit-doubles}.
+@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 MDUC registers will only be saved
+if the interrupt handler performs a multiplication or division
+operation or it calls another function.
+
@end table
@node RS/6000 and PowerPC Options