Hi DJ, The patch below makes some changes to the way the RL78 backend handles the generation of interrupt functions. Specifically it:
* Uses register bank 3 instead of register bank 0 inside the handler. * Tweaks the need_to_save() function so only those registers that will be clobbered by the handler are push onto the stack. * Provides support for a "naked" function attribute so that programmers can write their own mixed C/assembler interrupt handlers if they want to. Tested, with no regressions, on an rl78-elf target. OK to apply ? Cheers Nick gcc/ChangeLog 2013-05-01 Nick Clifton <ni...@redhat.com> * config/rl78/rl78.c (need_to_save): Make into a boolean function. Do not save register bank 0 registers in interrupt handlers. (rl78_attribute_table): Add "naked". (rl78_is_naked_func): New function. (rl78_expand_prologue): Skip prologue generation for naked functions. Switch to register bank 3 for interrupt handlers. (rl78_expand_epilogue): Skip epilogue generation for naked functions. Switch back to register bank 0 in interrupt handlers. * doc/extend.texi: Document that the RL78 backend supports the "naked" function attribute. Index: gcc/config/rl78/rl78.c =================================================================== --- gcc/config/rl78/rl78.c (revision 198496) +++ gcc/config/rl78/rl78.c (working copy) @@ -373,34 +373,42 @@ return true; } -/* Returns nonzero if the given register needs to be saved by the +/* Returns true if the given register needs to be saved by the current function. */ -static int -need_to_save (int regno) +static bool +need_to_save (unsigned int regno) { if (is_interrupt_func (cfun->decl)) { + /* We don't need to save registers that have + been reserved for interrupt handlers. */ + if (regno > 23) + return false; + + /* If the handler is a non-leaf function then it may call + non-interrupt aware routines which will happily clobber + any call_used registers, so we have to preserve them. */ + if (!crtl->is_leaf && call_used_regs[regno]) + return true; + + /* Interrupt functions do not use register bank 0. */ if (regno < 8) - return 1; /* don't know what devirt will need */ - if (regno > 23) - return 0; /* don't need to save interrupt registers */ - if (crtl->is_leaf) - { - return df_regs_ever_live_p (regno); - } - else - return 1; + return false; + + /* Otherwise we only have to save a register, call_used + or not, if it is used by this handler. */ + return df_regs_ever_live_p (regno); } if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) - return 1; + return true; if (fixed_regs[regno]) - return 0; + return false; if (crtl->calls_eh_return) - return 1; + return true; if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) - return 1; - return 0; + return true; + return false; } /* We use this to wrap all emitted insns in the prologue. */ @@ -499,6 +507,8 @@ false }, { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, false }, + { "naked", 0, 0, true, false, false, rl78_handle_func_attribute, + false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -825,6 +833,12 @@ return rv; } +static int +rl78_is_naked_func (void) +{ + return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE); +} + /* Expand the function prologue (from the prologue pattern). */ void rl78_expand_prologue (void) @@ -833,19 +847,22 @@ rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM); int rb = 0; + if (rl78_is_naked_func ()) + return; + + rb = is_interrupt_func (cfun->decl) ? -1 : 0; + if (!cfun->machine->computed) rl78_compute_frame_info (); if (flag_stack_usage_info) current_function_static_stack_size = cfun->machine->framesize; - if (is_interrupt_func (cfun->decl)) - emit_insn (gen_sel_rb (GEN_INT (0))); - for (i = 0; i < 16; i++) if (cfun->machine->need_to_push [i]) { int need_bank = i/4; + if (need_bank != rb) { emit_insn (gen_sel_rb (GEN_INT (need_bank))); @@ -853,7 +870,14 @@ } F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2)))); } - if (rb != 0) + + /* Interrupt functions use rb3 instead of rb0. */ + if (is_interrupt_func (cfun->decl)) + { + if (rb != 3) + emit_insn (gen_sel_rb (GEN_INT (3))); + } + else if (rb != 0) emit_insn (gen_sel_rb (GEN_INT (0))); if (frame_pointer_needed) @@ -877,6 +901,11 @@ rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM); int rb = 0; + if (rl78_is_naked_func ()) + return; + + rb = is_interrupt_func (cfun->decl) ? 3 : 0; + if (frame_pointer_needed) { emit_move_insn (gen_rtx_REG (HImode, STACK_POINTER_REGNUM), Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 198496) +++ gcc/doc/extend.texi (working copy) @@ -3142,7 +3142,7 @@ @item naked @cindex function without a prologue/epilogue code -Use this attribute on the ARM, AVR, MCORE, RX and SPU ports to indicate that +Use this attribute on the ARM, AVR, MCORE, RL78, RX and SPU ports to indicate that the specified function does not need prologue/epilogue sequences generated by the compiler. It is up to the programmer to provide these sequences. The only statements that can be safely included in naked functions are