void crx_expand_epilogue (void) { rtx return_reg; /* Nonzero if we need to return and pop only RA. This will generate a * different insn. This differentiate is for the peepholes for call as last * statement in function. */ int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM] && (sum_regs == UNITS_PER_WORD)); /* Return register. */ return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM); if (frame_pointer_needed) /* Restore the stack pointer with the frame pointers value */ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); if (size_for_adjusting_sp > 0) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size_for_adjusting_sp))); if (crx_interrupt_function_p ()) emit_jump_insn (gen_interrupt_return ()); else if (last_reg_to_save == -1) /* Nothing to pop */ /* Don't output jump for interrupt routine, only retx. */ emit_jump_insn (gen_indirect_jump_return ()); else if (only_popret_RA) emit_jump_insn (gen_popret_RA_return ()); else emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs))); }
static void mpushpop_str (char *stringbuffer, const char *mnemonic, char *mask) { if (strlen (mask) > 2 || crx_interrupt_function_p ()) /* needs 2-word instr. */ sprintf (stringbuffer, "\n\t%s\tsp, {%s}", mnemonic, mask); else /* single word instruction */ sprintf (stringbuffer, "\n\t%s\t%s", mnemonic, mask); }
static void crx_compute_save_regs (void) { unsigned int regno; /* initialize here so in case the function is no-return it will be -1. */ last_reg_to_save = -1; /* No need to save any registers if the function never returns. */ if (FUNC_IS_NORETURN_P (current_function_decl)) return; /* Initialize the number of bytes to be saved. */ sum_regs = 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (fixed_regs[regno]) { save_regs[regno] = 0; continue; } /* If this reg is used and not call-used (except RA), save it. */ if (crx_interrupt_function_p ()) { if (!current_function_is_leaf && call_used_regs[regno]) /* this is a volatile reg in a non-leaf interrupt routine - save it * for the sake of its sons. */ save_regs[regno] = 1; else if (df_regs_ever_live_p (regno)) /* This reg is used - save it. */ save_regs[regno] = 1; else /* This reg is not used, and is not a volatile - don't save. */ save_regs[regno] = 0; } else { /* If this reg is used and not call-used (except RA), save it. */ if (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM)) save_regs[regno] = 1; else save_regs[regno] = 0; } } for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (save_regs[regno] == 1) { last_reg_to_save = regno; sum_regs += UNITS_PER_WORD; } }
char * crx_prepare_push_pop_string (int push_or_pop) { /* j is the number of registers being saved, takes care that there won't be * more than 8 in one push/pop instruction */ /* For the register mask string */ static char mask_str[50]; /* i is the index of save_regs[], going from 0 until last_reg_to_save */ int i = 0; int ra_in_bitmask = 0; char *return_str; /* For reversing on the push instructions if there are more than one. */ char *temp_str; return_str = (char *) xmalloc (120); temp_str = (char *) xmalloc (120); /* Initialize */ memset (return_str, 0, 3); while (i <= last_reg_to_save) { /* Prepare mask for one instruction. */ mask_str[0] = 0; if (i <= SP_REGNUM) { /* Add regs unit full or SP register reached */ int j = 0; while (j < MAX_COUNT && i <= SP_REGNUM) { if (save_regs[i]) { /* TODO to use ra_in_bitmask for detecting last pop is not * smart it prevents things like: popret r5 */ if (i == RETURN_ADDRESS_REGNUM) ra_in_bitmask = 1; if (j > 0) strcat (mask_str, ", "); strcat (mask_str, reg_names[i]); ++j; } ++i; } } else { /* Handle hi/lo savings */ while (i <= last_reg_to_save) { if (save_regs[i]) { strcat (mask_str, "lo, hi"); i = last_reg_to_save + 1; break; } ++i; } } if (strlen (mask_str) == 0) continue; if (push_or_pop == 1) { if (crx_interrupt_function_p ()) mpushpop_str (temp_str, "popx", mask_str); else { if (ra_in_bitmask) { mpushpop_str (temp_str, "popret", mask_str); ra_in_bitmask = 0; } else mpushpop_str (temp_str, "pop", mask_str); } strcat (return_str, temp_str); } else { /* push - We need to reverse the order of the instructions if there * are more than one. (since the pop will not be reversed in the * epilogue */ if (crx_interrupt_function_p ()) mpushpop_str (temp_str, "pushx", mask_str); else mpushpop_str (temp_str, "push", mask_str); strcat (temp_str, return_str); strcpy (strcat (return_str, "\t"), temp_str); } } if (push_or_pop == 1) { /* pop */ if (crx_interrupt_function_p ()) strcat (return_str, "\n\tretx\n"); else if (!FUNC_IS_NORETURN_P (current_function_decl) && !save_regs[RETURN_ADDRESS_REGNUM]) strcat (return_str, "\n\tjump\tra\n"); } /* Skip the newline and the tab in the start of return_str. */ return_str += 2; return return_str; }