static void vax_output_function_prologue (FILE * file, HOST_WIDE_INT size) { int regno; int mask = 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) mask |= 1 << regno; fprintf (file, "\t.word 0x%x\n", mask); if (dwarf2out_do_frame ()) { const char *label = dwarf2out_cfi_label (); int offset = 0; for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno) if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) dwarf2out_reg_save (label, regno, offset -= 4); dwarf2out_reg_save (label, PC_REGNUM, offset -= 4); dwarf2out_reg_save (label, FRAME_POINTER_REGNUM, offset -= 4); dwarf2out_reg_save (label, ARG_POINTER_REGNUM, offset -= 4); dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4)); } size -= STARTING_FRAME_OFFSET; if (size >= 64) asm_fprintf (file, "\tmovab %wd(%Rsp),%Rsp\n", -size); else if (size) asm_fprintf (file, "\tsubl2 $%wd,%Rsp\n", size); }
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; } }
/* Return the bytes needed to compute the frame pointer from the current stack pointer. */ static HOST_WIDE_INT lm32_compute_frame_size (int size) { int regno; HOST_WIDE_INT total_size, locals_size, args_size, pretend_size, callee_size; unsigned int reg_save_mask; locals_size = size; args_size = crtl->outgoing_args_size; pretend_size = crtl->args.pretend_args_size; callee_size = 0; reg_save_mask = 0; /* Build mask that actually determines which regsiters we save and calculate size required to store them in the stack. */ for (regno = 1; regno < SP_REGNUM; regno++) { if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) { reg_save_mask |= 1 << regno; callee_size += UNITS_PER_WORD; } } if (df_regs_ever_live_p (RA_REGNUM) || ! crtl->is_leaf || !optimize) { reg_save_mask |= 1 << RA_REGNUM; callee_size += UNITS_PER_WORD; } if (!(reg_save_mask & (1 << FP_REGNUM)) && frame_pointer_needed) { reg_save_mask |= 1 << FP_REGNUM; callee_size += UNITS_PER_WORD; } /* Compute total frame size. */ total_size = pretend_size + args_size + locals_size + callee_size; /* Align frame to appropriate boundary. */ total_size = (total_size + 3) & ~3; /* Save computed information. */ current_frame_info.total_size = total_size; current_frame_info.callee_size = callee_size; current_frame_info.pretend_size = pretend_size; current_frame_info.locals_size = locals_size; current_frame_info.args_size = args_size; current_frame_info.reg_save_mask = reg_save_mask; return total_size; }
/* Support function to determine the return address of the function 'count' frames back up the stack. */ rtx lm32_return_addr_rtx (int count, rtx frame) { rtx r; if (count == 0) { if (!df_regs_ever_live_p (RA_REGNUM)) r = gen_rtx_REG (Pmode, RA_REGNUM); else { r = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, frame, GEN_INT (-2 * UNITS_PER_WORD))); set_mem_alias_set (r, get_frame_alias_set ()); } } else if (flag_omit_frame_pointer) r = NULL_RTX; else { r = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, frame, GEN_INT (-2 * UNITS_PER_WORD))); set_mem_alias_set (r, get_frame_alias_set ()); } return r; }
void moxie_expand_epilogue (void) { int regno; rtx reg; if (cfun->machine->callee_saved_reg_size != 0) { reg = gen_rtx_REG (Pmode, MOXIE_R12); if (cfun->machine->callee_saved_reg_size <= 255) { emit_move_insn (reg, hard_frame_pointer_rtx); emit_insn (gen_subsi3 (reg, reg, GEN_INT (cfun->machine->callee_saved_reg_size))); } else { emit_move_insn (reg, GEN_INT (-cfun->machine->callee_saved_reg_size)); emit_insn (gen_addsi3 (reg, reg, hard_frame_pointer_rtx)); } for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; ) if (!fixed_regs[regno] && !call_used_regs[regno] && df_regs_ever_live_p (regno)) { rtx preg = gen_rtx_REG (Pmode, regno); emit_insn (gen_movsi_pop (reg, preg)); } } emit_jump_insn (gen_returner ()); }
static void moxie_compute_frame (void) { /* For aligning the local variables. */ int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT; int padding_locals; int regno; /* Padding needed for each element of the frame. */ cfun->machine->local_vars_size = get_frame_size (); /* Align to the stack alignment. */ padding_locals = cfun->machine->local_vars_size % stack_alignment; if (padding_locals) padding_locals = stack_alignment - padding_locals; cfun->machine->local_vars_size += padding_locals; cfun->machine->callee_saved_reg_size = 0; /* Save callee-saved registers. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (df_regs_ever_live_p (regno) && (! call_used_regs[regno])) cfun->machine->callee_saved_reg_size += 4; cfun->machine->size_for_adjusting_sp = crtl->args.pretend_args_size + cfun->machine->local_vars_size + (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0); }
/* Support function to determine the return address of the function 'count' frames back up the stack. */ rtx lm32_return_addr_rtx (int count, rtx frame) { rtx r; if (count == 0) { /* *mjs* This test originally used leaf_function_p (), we now use the regs_ever_live test which I *think* is more accurate. */ if (!df_regs_ever_live_p(RA_REGNUM)) { r = gen_rtx_REG (Pmode, RA_REGNUM); } else { r = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, frame, GEN_INT(- 2 * UNITS_PER_WORD))); set_mem_alias_set (r, get_frame_alias_set ()); } } else if (flag_omit_frame_pointer) r = NULL_RTX; else { r = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, frame, GEN_INT(- 2 * UNITS_PER_WORD))); set_mem_alias_set (r, get_frame_alias_set ()); } return r; }
int registers_to_be_saved() { int i,num; for(i=0,num=0;i<FIRST_PSEUDO_REGISTER;i++) { if(df_regs_ever_live_p(i) && !call_used_regs[i] && !fixed_regs[i]) num++; } return num; }
void moxie_expand_prologue (void) { int regno; rtx insn; moxie_compute_frame (); if (flag_stack_usage_info) current_function_static_stack_size = cfun->machine->size_for_adjusting_sp; /* Save callee-saved registers. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno]) { insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno))); RTX_FRAME_RELATED_P (insn) = 1; } } if (cfun->machine->size_for_adjusting_sp > 0) { int i = cfun->machine->size_for_adjusting_sp; while ((i >= 255) && (i <= 510)) { insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (255))); RTX_FRAME_RELATED_P (insn) = 1; i -= 255; } if (i <= 255) { insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (i))); RTX_FRAME_RELATED_P (insn) = 1; } else { rtx reg = gen_rtx_REG (SImode, MOXIE_R12); insn = emit_move_insn (reg, GEN_INT (i)); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); RTX_FRAME_RELATED_P (insn) = 1; } } }
/* Return nonzero if this function is known to have a null epilogue. This allows the optimizer to omit jumps to jumps if no stack was created. */ int lm32_can_use_return (void) { if (!reload_completed) return 0; if (df_regs_ever_live_p (RA_REGNUM) || crtl->profile) return 0; if (lm32_compute_frame_size (get_frame_size ()) != 0) return 0; return 1; }
/* Returns a number of pushed registers */ static int msp430_func_num_saved_regs (void) { int i; int saves = 0; int interrupt_func_p = interrupt_function_p (current_function_decl); for (i = 4; i < 16; i++) { if ((df_regs_ever_live_p(i) && (!call_used_regs[i] || interrupt_func_p)) || (!cfun->machine->is_leaf && (call_used_regs[i] && interrupt_func_p))) { saves += 1; } } return saves; }
void moxie_expand_prologue (void) { int regno; rtx insn; moxie_compute_frame (); /* Save callee-saved registers. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno]) { insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno))); RTX_FRAME_RELATED_P (insn) = 1; } } if (cfun->machine->size_for_adjusting_sp > 0) { if (cfun->machine->size_for_adjusting_sp <= 255) { insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (cfun->machine->size_for_adjusting_sp))); RTX_FRAME_RELATED_P (insn) = 1; } else { insn = emit_insn (gen_movsi (gen_rtx_REG (Pmode, MOXIE_R5), GEN_INT (-cfun->machine->size_for_adjusting_sp))); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, gen_rtx_REG (Pmode, MOXIE_R5))); RTX_FRAME_RELATED_P (insn) = 1; } } }
static void recompute_gain_for_pattern_seq (pattern_seq pseq) { matching_seq mseq; rtx x; int i; int hascall; HARD_REG_SET linkregs; /* Initialize data. */ SET_HARD_REG_SET (linkregs); pseq->link_reg = NULL_RTX; pseq->abstracted_length = 0; pseq->gain = -(seq_call_cost - seq_jump_cost + seq_return_cost); /* Determine ABSTRACTED_LENGTH and COST for matching sequences of PSEQ. ABSTRACTED_LENGTH may be less than MATCHING_LENGTH if sequences in the same block overlap. */ for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq) { /* Determine ABSTRACTED_LENGTH. */ if (mseq->next_matching_seq) mseq->abstracted_length = (int)(mseq->next_matching_seq->idx - mseq->idx); else mseq->abstracted_length = mseq->matching_length; if (mseq->abstracted_length > mseq->matching_length) mseq->abstracted_length = mseq->matching_length; /* Compute the cost of sequence. */ RECOMPUTE_COST (mseq); /* If COST is big enough registers live in this matching sequence should not be used as a link register. Also set ABSTRACTED_LENGTH of PSEQ. */ if (mseq->cost > seq_call_cost) { clear_regs_live_in_seq (&linkregs, mseq->insn, mseq->abstracted_length); if (mseq->abstracted_length > pseq->abstracted_length) pseq->abstracted_length = mseq->abstracted_length; } } /* Modify ABSTRACTED_LENGTH of PSEQ if pattern sequence overlaps with one of the matching sequences. */ for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq) { x = pseq->insn; for (i = 0; (i < pseq->abstracted_length) && (x != mseq->insn); i++) x = prev_insn_in_block (x); pseq->abstracted_length = i; } /* Compute the cost of pattern sequence. */ RECOMPUTE_COST (pseq); /* No gain if COST is too small. */ if (pseq->cost <= seq_call_cost) { pseq->gain = -1; return; } /* Ensure that no matching sequence is longer than the pattern sequence. */ for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq) { if (mseq->abstracted_length > pseq->abstracted_length) { mseq->abstracted_length = pseq->abstracted_length; RECOMPUTE_COST (mseq); } /* Once the length is stabilizing the gain can be calculated. */ if (mseq->cost > seq_call_cost) pseq->gain += mseq->cost - seq_call_cost; } /* No need to do further work if there is no gain. */ if (pseq->gain <= 0) return; /* Should not use registers live in the pattern sequence as link register. */ clear_regs_live_in_seq (&linkregs, pseq->insn, pseq->abstracted_length); /* Determine whether pattern sequence contains a call_insn. */ hascall = 0; x = pseq->insn; for (i = 0; i < pseq->abstracted_length; i++) { if (CALL_P (x)) { hascall = 1; break; } x = prev_insn_in_block (x); } /* Should not use a register as a link register if - it is a fixed register, or - the sequence contains a call insn and the register is a call used register, or - the register needs to be saved if used in a function but was not used before (since saving it can invalidate already computed frame pointer offsets), or - the register cannot be used as a base register. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (fixed_regs[i] #ifdef REGNO_OK_FOR_INDIRECT_JUMP_P || (!REGNO_OK_FOR_INDIRECT_JUMP_P (i, Pmode)) #else || (!ok_for_base_p_1 (i, Pmode, MEM, SCRATCH)) || (!reg_class_subset_p (REGNO_REG_CLASS (i), base_reg_class (VOIDmode, MEM, SCRATCH))) #endif || (hascall && call_used_regs[i]) || (!call_used_regs[i] && !df_regs_ever_live_p (i))) CLEAR_HARD_REG_BIT (linkregs, i); /* Find an appropriate register to be used as the link register. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (linkregs, i)) { pseq->link_reg = gen_rtx_REG (Pmode, i); break; } /* Abstraction is not possible if no link register is available, so set gain to 0. */ if (!pseq->link_reg) pseq->gain = 0; }
void expand_epilogue (void) { int i; int interrupt_func_p = cfun->machine->is_interrupt; int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); int wakeup_func_p = cfun->machine->is_wakeup; int cfp = cfun->machine->is_critical; int ree = cfun->machine->is_reenterant; int save_prologue_p = msp430_save_prologue_function_p (current_function_decl); /*int function_size;*/ HOST_WIDE_INT size = get_frame_size(); rtx insn; last_insn_address = 0; jump_tables_size = 0; epilogue_size = 0; /*function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ())) - INSN_ADDRESSES (INSN_UID (get_insns ())));*/ if (cfun->machine->is_OS_task || cfun->machine->is_naked) { emit_jump_insn (gen_return ()); /* Otherwise, epilogue with 0 instruction causes a segmentation fault */ return; } if (msp430_empty_epilogue ()) { if (!return_issued) { /*fprintf (file, "\t%s\n", msp430_emit_return (NULL, NULL, NULL));*/ emit_jump_insn (gen_return ()); epilogue_size++; } /*fprintf (file, "\n\t/ * epilogue: not required * /\n");*/ goto done_epilogue; } if ((cfp || interrupt_func_p) && ree) ree = 0; if (cfp && interrupt_func_p) cfp = 0; /*fprintf (file, "\n\t/ * epilogue : frame size = %d * /\n", size);*/ if (main_p) { int totalsize = (size + 1) & ~1; if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size) totalsize += crtl->outgoing_args_size; if (totalsize) { msp430_fh_add_sp_const(totalsize); /*fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1);*/ } /*fprintf (file, "\tbr\t#%s\n", msp430_endup);*/ msp430_fh_br_to_symbol_plus_offset(msp430_endup, 0); epilogue_size += 4; if (size == 1 || size == 2 || size == 4 || size == 8) epilogue_size--; } else { int totalsize = (size + 1) & ~1; if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size) totalsize += crtl->outgoing_args_size; if (ree) { /*fprintf (file, "\teint\n");*/ insn = emit_insn (gen_enable_interrupt()); epilogue_size += 1; } if (totalsize) { /*fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1);*/ msp430_fh_add_sp_const(totalsize); if (size == 1 || size == 2 || size == 4 || size == 8) epilogue_size += 1; else epilogue_size += 2; } if ((TARGET_SAVE_PROLOGUE || save_prologue_p) && !interrupt_func_p && msp430_func_num_saved_regs () > 2) { /*fprintf (file, "\tbr\t#__epilogue_restorer+%d\n",(8 - msp430_func_num_saved_regs ()) * 2);*/ msp430_fh_br_to_symbol_plus_offset("__epilogue_restorer", (8 - msp430_func_num_saved_regs ()) * 2); epilogue_size += 2; } else if ((TARGET_SAVE_PROLOGUE || save_prologue_p) && interrupt_func_p) { /*fprintf (file, "\tbr\t#__epilogue_restorer_intr+%d\n", (12 - msp430_func_num_saved_regs ()) * 2);*/ msp430_fh_br_to_symbol_plus_offset("__epilogue_restorer_intr", (12 - msp430_func_num_saved_regs ()) * 2); } else { for (i = 4; i < 16; i++) { if ((df_regs_ever_live_p(i) && (!call_used_regs[i] || interrupt_func_p)) || (!cfun->machine->is_leaf && (call_used_regs[i] && interrupt_func_p))) { /*fprintf (file, "\tpop\tr%d\n", i);*/ msp430_fh_emit_pop_reg(i); epilogue_size += 1; } } if (interrupt_func_p && wakeup_func_p) { /*fprintf (file, "\tbic\t#0xf0,0(r1)\n");*/ msp430_fh_bic_deref_sp(0xF0); epilogue_size += 3; } emit_jump_insn (gen_return ()); /*fprintf (file, "\tret\n");*/ epilogue_size += 1; } } /*fprintf (file, "\t/ * epilogue end (size=%d) * /\n", epilogue_size);*/ done_epilogue: /*fprintf (file, "\t/ * function %s size %d (%d) * /\n", current_function_name, prologue_size + function_size + epilogue_size, function_size);*/ msp430_commands_in_file += prologue_size + /*function_size +*/ epilogue_size; msp430_commands_in_prologues += prologue_size; msp430_commands_in_epilogues += epilogue_size; }
void expand_prologue (void) { int i; int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); int stack_reserve = 0; int offset; int save_prologue_p = msp430_save_prologue_function_p (current_function_decl); int num_saved_regs; HOST_WIDE_INT size = get_frame_size(); rtx insn; /* Last generated instruction */ return_issued = 0; last_insn_address = 0; jump_tables_size = 0; prologue_size = 0; cfun->machine->is_naked = msp430_naked_function_p (current_function_decl); cfun->machine->is_interrupt = interrupt_function_p (current_function_decl); cfun->machine->is_OS_task = msp430_task_function_p (current_function_decl); cfun->machine->is_noint_hwmul = noint_hwmul_function_p (current_function_decl); cfun->machine->is_critical = msp430_critical_function_p(current_function_decl); cfun->machine->is_reenterant = msp430_reentrant_function_p(current_function_decl); cfun->machine->is_wakeup = wakeup_function_p (current_function_decl); cfun->machine->is_signal = signal_function_p (current_function_decl); /* check attributes compatibility */ if ((cfun->machine->is_critical && cfun->machine->is_reenterant) || (cfun->machine->is_reenterant && cfun->machine->is_interrupt)) { warning (OPT_Wattributes, "attribute 'reentrant' ignored"); cfun->machine->is_reenterant = 0; } if (cfun->machine->is_critical && cfun->machine->is_interrupt) { warning (OPT_Wattributes, "attribute 'critical' ignored"); cfun->machine->is_critical = 0; } if (cfun->machine->is_signal && !cfun->machine->is_interrupt) { warning (OPT_Wattributes, "attribute 'signal' has no meaning on MSP430 without 'interrupt' attribute."); cfun->machine->is_signal = 0; } /* naked function discards everything */ if (cfun->machine->is_naked) return; stack_reserve = msp430_get_stack_reserve(); offset = initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM) - 2; msp430_current_frame_offset = offset; if (cfun->machine->is_signal && cfun->machine->is_interrupt) { prologue_size += 1; insn = emit_insn (gen_enable_interrupt()); /* fprintf (file, "\teint\t; enable nested interrupt\n"); */ } if (main_p) { if (TARGET_NO_STACK_INIT) { if (size || stack_reserve) { /* fprintf (file, "\tsub\t#%d, r1\t", size + stack_reserve); */ msp430_fh_sub_sp_const(size + stack_reserve); } if (frame_pointer_needed) { /* fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); */ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; prologue_size += 1; } if (size) prologue_size += 2; if (size == 1 || size == 2 || size == 4 || size == 8) prologue_size--; } else { /*fprintf (file, "\tmov\t#(%s-%d), r1\n", msp430_init_stack, size + stack_reserve);*/ msp430_fh_load_sp_with_sym_plus_off(msp430_init_stack, -(size + stack_reserve)); if (frame_pointer_needed) { /* fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); */ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; prologue_size += 1; } prologue_size += 2; } if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size) msp430_fh_sub_sp_const(crtl->outgoing_args_size); } else /* not a main() function */ { /* Here, we've got a chance to jump to prologue saver */ num_saved_regs = msp430_func_num_saved_regs (); if (!cfun->machine->is_interrupt && cfun->machine->is_critical) { prologue_size += 3; /*fprintf (file, "\tpush\tr2\n"); fprintf (file, "\tdint\n"); if (!size) fprintf (file, "\tnop\n");*/ insn = emit_insn (gen_push_sreg()); /* Pushing R2 using normal push creates a faulty INSN */ RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_disable_interrupt()); if (!size) insn = emit_insn (gen_nop()); } if ((TARGET_SAVE_PROLOGUE || save_prologue_p) && !cfun->machine->is_interrupt && !arg_register_used[12] && num_saved_regs > 4) { /* TODO: Expand this as a separate INSN called "call prologue saver", having a meaning of pushing the registers and decreasing SP, so that the debug info generation code will handle this correctly */ /*fprintf (file, "\tsub\t#16, r1\n"); fprintf (file, "\tmov\tr0, r12\n"); fprintf (file, "\tadd\t#8, r12\n"); fprintf (file, "\tbr\t#__prologue_saver+%d\n", (8 - num_saved_regs) * 4);*/ msp430_fh_sub_sp_const(16); msp430_fh_gen_mov_pc_to_reg(12); msp430_fh_add_reg_const(12, 8); msp430_fh_br_to_symbol_plus_offset("__prologue_saver", (8 - num_saved_regs) * 4); if (cfun->machine->is_critical && 8 - num_saved_regs) { int n = 16 - num_saved_regs * 2; /*fprintf (file, "\tadd\t#%d, r1\n", n);*/ msp430_fh_add_sp_const(n); if (n != 0 && n != 1 && n != 2 && n != 4 && n != 8) prologue_size += 1; } else size -= 16 - num_saved_regs * 2; prologue_size += 7; } else if(!cfun->machine->is_OS_task) { for (i = 15; i >= 4; i--) { if ((df_regs_ever_live_p(i) && (!call_used_regs[i] || cfun->machine->is_interrupt)) || (!cfun->machine->is_leaf && (call_used_regs[i] && (cfun->machine->is_interrupt)))) { /*fprintf (file, "\tpush\tr%d\n", i);*/ msp430_fh_emit_push_reg(i); prologue_size += 1; } } } if (size) { /* The next is a hack... I do not understand why, but if there ARG_POINTER_REGNUM and FRAME/STACK are different, the compiler fails to compute corresponding displacement */ if (!optimize && !optimize_size && df_regs_ever_live_p(ARG_POINTER_REGNUM)) { int o = initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM) - size; /* fprintf (file, "\tmov\tr1, r%d\n", ARG_POINTER_REGNUM); fprintf (file, "\tadd\t#%d, r%d\n", o, ARG_POINTER_REGNUM); */ insn = emit_move_insn (arg_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; msp430_fh_add_reg_const(ARG_POINTER_REGNUM, o); prologue_size += 2; if (o != 0 && o != 1 && o != 2 && o != 4 && o != 8) prologue_size += 1; } /* adjust frame ptr... */ if (size < 0) { int subtracted = (size + 1) & ~1; /*fprintf (file, "\tsub\t#%d, r1\t; %d, fpn %d\n", subtracted, size, frame_pointer_needed);*/ msp430_fh_sub_sp_const(subtracted); } else { int added; size = -size; added = (size + 1) & ~1; /*fprintf (file, "\tadd\t#%d, r1\t; %d, fpn %d\n", (size + 1) & ~1, size, frame_pointer_needed);*/ msp430_fh_add_sp_const(added); } if (size == 1 || size == 2 || size == 4 || size == 8) prologue_size += 1; else prologue_size += 2; } if (frame_pointer_needed) { /*fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM);*/ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; prologue_size += 1; } if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size) msp430_fh_sub_sp_const(crtl->outgoing_args_size); /* disable interrupt for reentrant function */ if (!cfun->machine->is_interrupt && cfun->machine->is_reenterant) { prologue_size += 1; /*fprintf (file, "\tdint\n");*/ insn = emit_insn (gen_disable_interrupt()); } } /*fprintf (file, "\t/ * prologue end (size=%d) * /\n\n", prologue_size);*/ }