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);*/ }
static void tree_expand_cfg (void) { basic_block bb, init_block; sbitmap blocks; /* Some backends want to know that we are expanding to RTL. */ currently_expanding_to_rtl = 1; /* Prepare the rtl middle end to start recording block changes. */ reset_block_changes (); /* Expand the variables recorded during gimple lowering. */ expand_used_vars (); #ifdef KEY // Run expand_used_vars above to set DECL_SECTION_NAME. Bug 10876. if (flag_spin_file) return; #endif /* Set up parameters and prepare for return, for the function. */ expand_function_start (current_function_decl); /* If this function is `main', emit a call to `__main' to run global initializers, etc. */ if (DECL_NAME (current_function_decl) && MAIN_NAME_P (DECL_NAME (current_function_decl)) && DECL_FILE_SCOPE_P (current_function_decl)) expand_main_function (); /* Register rtl specific functions for cfg. */ rtl_register_cfg_hooks (); init_block = construct_init_block (); FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb) bb = expand_gimple_basic_block (bb, dump_file); construct_exit_block (); /* We're done expanding trees to RTL. */ currently_expanding_to_rtl = 0; /* Convert tree EH labels to RTL EH labels, and clean out any unreachable EH regions. */ convert_from_eh_region_ranges (); rebuild_jump_labels (get_insns ()); find_exception_handler_labels (); blocks = sbitmap_alloc (last_basic_block); sbitmap_ones (blocks); find_many_sub_basic_blocks (blocks); purge_all_dead_edges (0); sbitmap_free (blocks); compact_blocks (); #ifdef ENABLE_CHECKING verify_flow_info(); #endif /* There's no need to defer outputting this function any more; we know we want to output it. */ DECL_DEFER_OUTPUT (current_function_decl) = 0; /* Now that we're done expanding trees to RTL, we shouldn't have any more CONCATs anywhere. */ generating_concat_p = 0; finalize_block_changes (); if (dump_file) { fprintf (dump_file, "\n\n;;\n;; Full RTL generated for this function:\n;;\n"); /* And the pass manager will dump RTL for us. */ } }