Exemplo n.º 1
0
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);*/
}
Exemplo n.º 2
0
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.  */
    }
}