gcc 源码分析:从IR-RTL 到汇编输出

在完成了IR-RTL的优化与寄存器分配后

就来到汇编代码的输出:

实现如下:

class pass_final : public rtl_opt_pass
{
public:
  pass_final (gcc::context *ctxt)
    : rtl_opt_pass (pass_data_final, ctxt)
  {}

  /* opt_pass methods: */
  unsigned int execute (function *) final override
  {
    return rest_of_handle_final ();
  }

}; // class pass_final

} // anon namespace

rest_of_handle_final (void)
{
  const char *fnname = get_fnname_from_decl (current_function_decl);

  /* Turn debug markers into notes if the var-tracking pass has not
     been invoked.  */
  if (!flag_var_tracking && MAY_HAVE_DEBUG_MARKER_INSNS)
    delete_vta_debug_insns (false);

  assemble_start_function (current_function_decl, fnname);
  rtx_insn *first = get_insns ();
  int seen = 0;
  final_start_function_1 (&first, asm_out_file, &seen, optimize);
  final_1 (first, asm_out_file, seen, optimize);
  if (flag_ipa_ra
      && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl))
      /* Functions with naked attributes are supported only with basic asm
     statements in the body, thus for supported use cases the information
     on clobbered registers is not available.  */
      && !lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)))
    collect_fn_hard_reg_usage ();
  final_end_function ();

  /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
     directive that closes the procedure descriptor.  Similarly, for x64 SEH.
     Otherwise it's not strictly necessary, but it doesn't hurt either.  */
  output_function_exception_table (crtl->has_bb_partition ? 1 : 0);

  assemble_end_function (current_function_decl, fnname);

  /* Free up reg info memory.  */
  free_reg_info ();

  if (! quiet_flag)
    fflush (asm_out_file);

  /* Note that for those inline functions where we don't initially
     know for certain that we will be generating an out-of-line copy,
     the first invocation of this routine (rest_of_compilation) will
     skip over this code by doing a `goto exit_rest_of_compilation;'.
     Later on, wrapup_global_declarations will (indirectly) call
     rest_of_compilation again for those inline functions that need
     to have out-of-line copies generated.  During that call, we
     *will* be routed past here.  */

  timevar_push (TV_SYMOUT);
  if (!DECL_IGNORED_P (current_function_decl))
    debug_hooks->function_decl (current_function_decl);
  timevar_pop (TV_SYMOUT);

  /* Release the blocks that are linked to DECL_INITIAL() to free the memory.  */
  DECL_INITIAL (current_function_decl) = error_mark_node;

  if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
      && targetm.have_ctors_dtors)
    targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
                 decl_init_priority_lookup
                   (current_function_decl));
  if (DECL_STATIC_DESTRUCTOR (current_function_decl)
      && targetm.have_ctors_dtors)
    targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0),
                decl_fini_priority_lookup
                  (current_function_decl));
  return 0;
}

static void
final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)

{
  rtx_insn *insn, *next;

  /* Used for -dA dump.  */
  basic_block *start_to_bb = NULL;
  basic_block *end_to_bb = NULL;
  int bb_map_size = 0;
  int bb_seqn = 0;

  last_ignored_compare = 0;

  init_recog ();

  CC_STATUS_INIT;

  if (flag_debug_asm)
    {
      basic_block bb;

      bb_map_size = get_max_uid () + 1;
      start_to_bb = XCNEWVEC (basic_block, bb_map_size);
      end_to_bb = XCNEWVEC (basic_block, bb_map_size);

      /* There is no cfg for a thunk.  */
      if (!cfun->is_thunk)
    FOR_EACH_BB_REVERSE_FN (bb, cfun)
      {
        start_to_bb[INSN_UID (BB_HEAD (bb))] = bb;
        end_to_bb[INSN_UID (BB_END (bb))] = bb;
      }
    }

  /* Output the insns.  */
  for (insn = first; insn;)
    {
      if (HAVE_ATTR_length)
    {
      if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
        {
          /* This can be triggered by bugs elsewhere in the compiler if
         new insns are created after init_insn_lengths is called.  */
          gcc_assert (NOTE_P (insn));
          insn_current_address = -1;
        }
      else
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
      /* final can be seen as an iteration of shorten_branches that
         does nothing (since a fixed point has already been reached).  */
      insn_last_address = insn_current_address;
    }

      dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
                             bb_map_size, &bb_seqn);
      insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
    }

  maybe_output_next_view (&seen);

  if (flag_debug_asm)
    {
      free (start_to_bb);
      free (end_to_bb);
    }

  /* Remove CFI notes, to avoid compare-debug failures.  */
  for (insn = first; insn; insn = next)
    {
      next = NEXT_INSN (insn);
      if (NOTE_P (insn)
      && (NOTE_KIND (insn) == NOTE_INSN_CFI
          || NOTE_KIND (insn) == NOTE_INSN_CFI_LABEL))
    delete_insn (insn);
    }
}

rtx_insn *
final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
         int nopeepholes, int *seen)

{
  static int *enclosing_seen;
  static int recursion_counter;

  gcc_assert (seen || recursion_counter);
  gcc_assert (!recursion_counter || !seen || seen == enclosing_seen);

  if (!recursion_counter++)
    enclosing_seen = seen;
  else if (!seen)
    seen = enclosing_seen;

  rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen);

  if (!--recursion_counter)
    enclosing_seen = NULL;

  return ret;
}

static rtx_insn *
final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
           int nopeepholes ATTRIBUTE_UNUSED, int *seen)

{
  rtx_insn *next;
  rtx_jump_table_data *table;

  insn_counter++;

  /* Ignore deleted insns.  These can occur when we split insns (due to a
     template of "#") while not optimizing.  */
  if (insn->deleted ())
    return NEXT_INSN (insn);

  switch (GET_CODE (insn))
    {
    case NOTE:
      switch (NOTE_KIND (insn))
    {
    case NOTE_INSN_DELETED:
    case NOTE_INSN_UPDATE_SJLJ_CONTEXT:
      break;

    case NOTE_INSN_SWITCH_TEXT_SECTIONS:
      maybe_output_next_view (seen);

      output_function_exception_table (0);

      if (targetm.asm_out.unwind_emit)
        targetm.asm_out.unwind_emit (asm_out_file, insn);

      in_cold_section_p = !in_cold_section_p;

      gcc_checking_assert (in_cold_section_p);
      if (in_cold_section_p)
        cold_function_name
          = clone_function_name (current_function_decl, "cold");

      if (dwarf2out_do_frame ())
        {
          dwarf2out_switch_text_section ();
          if (!dwarf2_debug_info_emitted_p (current_function_decl)
          && !DECL_IGNORED_P (current_function_decl))
        debug_hooks->switch_text_section ();
        }
      else if (!DECL_IGNORED_P (current_function_decl))
        debug_hooks->switch_text_section ();
      if (DECL_IGNORED_P (current_function_decl) && last_linenum
          && last_filename)
        debug_hooks->set_ignored_loc (last_linenum, last_columnnum,
                      last_filename);

      switch_to_section (current_function_section ());
      targetm.asm_out.function_switched_text_sections (asm_out_file,
                               current_function_decl,
                               in_cold_section_p);
      /* Emit a label for the split cold section.  Form label name by
         suffixing "cold" to the original function's name.  */
      if (in_cold_section_p)
        {
#ifdef ASM_DECLARE_COLD_FUNCTION_NAME
          ASM_DECLARE_COLD_FUNCTION_NAME (asm_out_file,
                          IDENTIFIER_POINTER
                              (cold_function_name),
                          current_function_decl);
#else
          ASM_OUTPUT_LABEL (asm_out_file,
                IDENTIFIER_POINTER (cold_function_name));
#endif
          if (dwarf2out_do_frame ()
              && cfun->fde->dw_fde_second_begin != NULL)
        ASM_OUTPUT_LABEL (asm_out_file, cfun->fde->dw_fde_second_begin);
        }
      break;

    case NOTE_INSN_BASIC_BLOCK:
      if (need_profile_function)
        {
          profile_function (asm_out_file);
          need_profile_function = false;
        }

      if (targetm.asm_out.unwind_emit)
        targetm.asm_out.unwind_emit (asm_out_file, insn);

      break;

    case NOTE_INSN_EH_REGION_BEG:
      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
                  NOTE_EH_HANDLER (insn));
      break;

    case NOTE_INSN_EH_REGION_END:
      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
                  NOTE_EH_HANDLER (insn));
      break;

    case NOTE_INSN_PROLOGUE_END:
      targetm.asm_out.function_end_prologue (file);
      profile_after_prologue (file);

      if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
        {
          *seen |= SEEN_EMITTED;
          force_source_line = true;
        }
      else
        *seen |= SEEN_NOTE;

      break;

    case NOTE_INSN_EPILOGUE_BEG:
          if (!DECL_IGNORED_P (current_function_decl))
            (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
      targetm.asm_out.function_begin_epilogue (file);
      break;

    case NOTE_INSN_CFI:
      dwarf2out_emit_cfi (NOTE_CFI (insn));
      break;

    case NOTE_INSN_CFI_LABEL:
      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI",
                  NOTE_LABEL_NUMBER (insn));
      break;

    case NOTE_INSN_FUNCTION_BEG:
      if (need_profile_function)
        {
          profile_function (asm_out_file);
          need_profile_function = false;
        }

      app_disable ();
      if (!DECL_IGNORED_P (current_function_decl))
        debug_hooks->end_prologue (last_linenum, last_filename);

      if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
        {
          *seen |= SEEN_EMITTED;
          force_source_line = true;
        }
      else
        *seen |= SEEN_NOTE;

      break;

    case NOTE_INSN_BLOCK_BEG:
      if (debug_info_level >= DINFO_LEVEL_NORMAL
          || dwarf_debuginfo_p ()
          || write_symbols == VMS_DEBUG)
        {
          int n = BLOCK_NUMBER (NOTE_BLOCK (insn));

          app_disable ();
          ++block_depth;
          high_block_linenum = last_linenum;

          /* Output debugging info about the symbol-block beginning.  */
          if (!DECL_IGNORED_P (current_function_decl))
        debug_hooks->begin_block (last_linenum, n, NOTE_BLOCK (insn));

          /* Mark this block as output.  */
          TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
          BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p;
        }
      break;

    case NOTE_INSN_BLOCK_END:
      maybe_output_next_view (seen);

      if (debug_info_level >= DINFO_LEVEL_NORMAL
          || dwarf_debuginfo_p ()
          || write_symbols == VMS_DEBUG)
        {
          int n = BLOCK_NUMBER (NOTE_BLOCK (insn));

          app_disable ();

          /* End of a symbol-block.  */
          --block_depth;
          gcc_assert (block_depth >= 0);

          if (!DECL_IGNORED_P (current_function_decl))
        debug_hooks->end_block (high_block_linenum, n);
          gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn))
              == in_cold_section_p);
        }
      break;

    case NOTE_INSN_DELETED_LABEL:
      /* Emit the label.  We may have deleted the CODE_LABEL because
         the label could be proved to be unreachable, though still
         referenced (in the form of having its address taken.  */
      ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
      break;

    case NOTE_INSN_DELETED_DEBUG_LABEL:
      /* Similarly, but need to use different namespace for it.  */
      if (CODE_LABEL_NUMBER (insn) != -1)
        ASM_OUTPUT_DEBUG_LABEL (file, "LDL", CODE_LABEL_NUMBER (insn));
      break;

    case NOTE_INSN_VAR_LOCATION:
      if (!DECL_IGNORED_P (current_function_decl))
        {
          debug_hooks->var_location (insn);
          set_next_view_needed (seen);
        }
      break;

    case NOTE_INSN_BEGIN_STMT:
      gcc_checking_assert (cfun->debug_nonbind_markers);
      if (!DECL_IGNORED_P (current_function_decl)
          && notice_source_line (insn, NULL))
        {
        output_source_line:
          (*debug_hooks->source_line) (last_linenum, last_columnnum,
                       last_filename, last_discriminator,
                       true);
          clear_next_view_needed (seen);
        }
      break;

    case NOTE_INSN_INLINE_ENTRY:
      gcc_checking_assert (cfun->debug_nonbind_markers);
      if (!DECL_IGNORED_P (current_function_decl)
          && notice_source_line (insn, NULL))
        {
          (*debug_hooks->inline_entry) (LOCATION_BLOCK
                        (NOTE_MARKER_LOCATION (insn)));
          goto output_source_line;
        }
      break;

    default:
      gcc_unreachable ();
      break;
    }
      break;

    case BARRIER:
      break;

    case CODE_LABEL:
      /* The target port might emit labels in the output function for
     some insn, e.g. sh.cc output_branchy_insn.  */
      if (CODE_LABEL_NUMBER (insn) <= max_labelno)
    {
      align_flags alignment = LABEL_TO_ALIGNMENT (insn);
      if (alignment.levels[0].log && NEXT_INSN (insn))
        {
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
          /* Output both primary and secondary alignment.  */
          ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[0].log,
                     alignment.levels[0].maxskip);
          ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[1].log,
                     alignment.levels[1].maxskip);
#else
#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
              ASM_OUTPUT_ALIGN_WITH_NOP (file, alignment.levels[0].log);
#else
          ASM_OUTPUT_ALIGN (file, alignment.levels[0].log);
#endif
#endif
        }
    }
      CC_STATUS_INIT;

      if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
    debug_hooks->label (as_a <rtx_code_label *> (insn));

      app_disable ();

      /* If this label is followed by a jump-table, make sure we put
     the label in the read-only section.  Also possibly write the
     label and jump table together.  */
      table = jump_table_for_label (as_a <rtx_code_label *> (insn));
      if (table)
    {
#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
      /* In this case, the case vector is being moved by the
         target, so don't output the label at all.  Leave that
         to the back end macros.  */
#else
      if (! JUMP_TABLES_IN_TEXT_SECTION)
        {
          int log_align;

          switch_to_section (targetm.asm_out.function_rodata_section
                 (current_function_decl,
                  jumptable_relocatable ()));

#ifdef ADDR_VEC_ALIGN
          log_align = ADDR_VEC_ALIGN (table);
#else
          log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
#endif
          ASM_OUTPUT_ALIGN (file, log_align);
        }
      else
        switch_to_section (current_function_section ());

#ifdef ASM_OUTPUT_CASE_LABEL
      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), table);
#else
      targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
#endif
#endif
      break;
    }
      if (LABEL_ALT_ENTRY_P (insn))
    output_alternate_entry_point (file, insn);
      else
    targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
      break;

    default:
      {
    rtx body = PATTERN (insn);
    int insn_code_number;
    const char *templ;
    bool is_stmt, *is_stmt_p;

    if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
      {
        is_stmt = false;
        is_stmt_p = NULL;
      }
    else
      is_stmt_p = &is_stmt;

    /* Reset this early so it is correct for ASM statements.  */
    current_insn_predicate = NULL_RTX;

    /* An INSN, JUMP_INSN or CALL_INSN.
       First check for special kinds that recog doesn't recognize.  */

    if (GET_CODE (body) == USE /* These are just declarations.  */
        || GET_CODE (body) == CLOBBER)
      break;

    /* Detect insns that are really jump-tables
       and output them as such.  */

        if (JUMP_TABLE_DATA_P (insn))
      {
#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
        int vlen, idx;
#endif

        if (! JUMP_TABLES_IN_TEXT_SECTION)
          switch_to_section (targetm.asm_out.function_rodata_section
                 (current_function_decl,
                  jumptable_relocatable ()));
        else
          switch_to_section (current_function_section ());

        app_disable ();

#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
        if (GET_CODE (body) == ADDR_VEC)
          {
#ifdef ASM_OUTPUT_ADDR_VEC
        ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
#else
        gcc_unreachable ();
#endif
          }
        else
          {
#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
        ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
#else
        gcc_unreachable ();
#endif
          }
#else
        vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
        for (idx = 0; idx < vlen; idx++)
          {
        if (GET_CODE (body) == ADDR_VEC)
          {
#ifdef ASM_OUTPUT_ADDR_VEC_ELT
            ASM_OUTPUT_ADDR_VEC_ELT
              (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
#else
            gcc_unreachable ();
#endif
          }
        else
          {
#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
            ASM_OUTPUT_ADDR_DIFF_ELT
              (file,
               body,
               CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
               CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
#else
            gcc_unreachable ();
#endif
          }
          }
#ifdef ASM_OUTPUT_CASE_END
        ASM_OUTPUT_CASE_END (file,
                 CODE_LABEL_NUMBER (PREV_INSN (insn)),
                 insn);
#endif
#endif

        switch_to_section (current_function_section ());

        if (debug_variable_location_views
        && !DECL_IGNORED_P (current_function_decl))
          debug_hooks->var_location (insn);

        break;
      }
    /* Output this line note if it is the first or the last line
       note in a row.  */
    if (!DECL_IGNORED_P (current_function_decl)
        && notice_source_line (insn, is_stmt_p))
      {
        if (flag_verbose_asm)
          asm_show_source (last_filename, last_linenum);
        (*debug_hooks->source_line) (last_linenum, last_columnnum,
                     last_filename, last_discriminator,
                     is_stmt);
        clear_next_view_needed (seen);
      }
    else
      maybe_output_next_view (seen);

    gcc_checking_assert (!DEBUG_INSN_P (insn));

    if (GET_CODE (body) == PARALLEL
        && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
      body = XVECEXP (body, 0, 0);

    if (GET_CODE (body) == ASM_INPUT)
      {
        const char *string = XSTR (body, 0);

        /* There's no telling what that did to the condition codes.  */
        CC_STATUS_INIT;

        if (string[0])
          {
        expanded_location loc;

        app_enable ();
        loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
        if (*loc.file && loc.line)
          fprintf (asm_out_file, "%s %i \"%s\" 1\n",
               ASM_COMMENT_START, loc.line, loc.file);
        fprintf (asm_out_file, "\t%s\n", string);
#if HAVE_AS_LINE_ZERO
        if (*loc.file && loc.line)
          fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
#endif
          }
        break;
      }

    /* Detect `asm' construct with operands.  */
    if (asm_noperands (body) >= 0)
      {
        unsigned int noperands = asm_noperands (body);
        rtx *ops = XALLOCAVEC (rtx, noperands);
        const char *string;
        location_t loc;
        expanded_location expanded;

        /* There's no telling what that did to the condition codes.  */
        CC_STATUS_INIT;

        /* Get out the operand values.  */
        string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
        /* Inhibit dying on what would otherwise be compiler bugs.  */
        insn_noperands = noperands;
        this_is_asm_operands = insn;
        expanded = expand_location (loc);

#ifdef FINAL_PRESCAN_INSN
        FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
#endif

        /* Output the insn using them.  */
        if (string[0])
          {
        app_enable ();
        if (expanded.file && expanded.line)
          fprintf (asm_out_file, "%s %i \"%s\" 1\n",
               ASM_COMMENT_START, expanded.line, expanded.file);
            output_asm_insn (string, ops);
#if HAVE_AS_LINE_ZERO
        if (expanded.file && expanded.line)
          fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
#endif
          }

        if (targetm.asm_out.final_postscan_insn)
          targetm.asm_out.final_postscan_insn (file, insn, ops,
                           insn_noperands);

        this_is_asm_operands = 0;
        break;
      }

    app_disable ();

    if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (body))
      {
        /* A delayed-branch sequence */
        int i;

        final_sequence = seq;

        /* The first insn in this SEQUENCE might be a JUMP_INSN that will
           force the restoration of a comparison that was previously
           thought unnecessary.  If that happens, cancel this sequence
           and cause that insn to be restored.  */

        next = final_scan_insn (seq->insn (0), file, 0, 1, seen);
        if (next != seq->insn (1))
          {
        final_sequence = 0;
        return next;
          }

        for (i = 1; i < seq->len (); i++)
          {
        rtx_insn *insn = seq->insn (i);
        rtx_insn *next = NEXT_INSN (insn);
        /* We loop in case any instruction in a delay slot gets
           split.  */
        do
          insn = final_scan_insn (insn, file, 0, 1, seen);
        while (insn != next);
          }
#ifdef DBR_OUTPUT_SEQEND
        DBR_OUTPUT_SEQEND (file);
#endif
        final_sequence = 0;

        /* If the insn requiring the delay slot was a CALL_INSN, the
           insns in the delay slot are actually executed before the
           called function.  Hence we don't preserve any CC-setting
           actions in these insns and the CC must be marked as being
           clobbered by the function.  */
        if (CALL_P (seq->insn (0)))
          {
        CC_STATUS_INIT;
          }
        break;
      }

    /* We have a real machine instruction as rtl.  */

    body = PATTERN (insn);

    /* Do machine-specific peephole optimizations if desired.  */

    if (HAVE_peephole && optimize_p && !flag_no_peephole && !nopeepholes)
      {
        rtx_insn *next = peephole (insn);
        /* When peepholing, if there were notes within the peephole,
           emit them before the peephole.  */
        if (next != 0 && next != NEXT_INSN (insn))
          {
        rtx_insn *note, *prev = PREV_INSN (insn);

        for (note = NEXT_INSN (insn); note != next;
             note = NEXT_INSN (note))
          final_scan_insn (note, file, optimize_p, nopeepholes, seen);

        /* Put the notes in the proper position for a later
           rescan.  For example, the SH target can do this
           when generating a far jump in a delayed branch
           sequence.  */
        note = NEXT_INSN (insn);
        SET_PREV_INSN (note) = prev;
        SET_NEXT_INSN (prev) = note;
        SET_NEXT_INSN (PREV_INSN (next)) = insn;
        SET_PREV_INSN (insn) = PREV_INSN (next);
        SET_NEXT_INSN (insn) = next;
        SET_PREV_INSN (next) = insn;
          }

        /* PEEPHOLE might have changed this.  */
        body = PATTERN (insn);
      }

    /* Try to recognize the instruction.
       If successful, verify that the operands satisfy the
       constraints for the instruction.  Crash if they don't,
       since `reload' should have changed them so that they do.  */

    insn_code_number = recog_memoized (insn);
    cleanup_subreg_operands (insn);

    /* Dump the insn in the assembly for debugging (-dAP).
       If the final dump is requested as slim RTL, dump slim
       RTL to the assembly file also.  */
    if (flag_dump_rtl_in_asm)
      {
        print_rtx_head = ASM_COMMENT_START;
        if (! (dump_flags & TDF_SLIM))
          print_rtl_single (asm_out_file, insn);
        else
          dump_insn_slim (asm_out_file, insn);
        print_rtx_head = "";
      }

    if (! constrain_operands_cached (insn, 1))
      fatal_insn_not_found (insn);

    /* Some target machines need to prescan each insn before
       it is output.  */

#ifdef FINAL_PRESCAN_INSN
    FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
#endif

    if (targetm.have_conditional_execution ()
        && GET_CODE (PATTERN (insn)) == COND_EXEC)
      current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));

    current_output_insn = debug_insn = insn;

    /* Find the proper template for this insn.  */
    templ = get_insn_template (insn_code_number, insn);

    /* If the C code returns 0, it means that it is a jump insn
       which follows a deleted test insn, and that test insn
       needs to be reinserted.  */
    if (templ == 0)
      {
        rtx_insn *prev;

        gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);

        /* We have already processed the notes between the setter and
           the user.  Make sure we don't process them again, this is
           particularly important if one of the notes is a block
           scope note or an EH note.  */
        for (prev = insn;
         prev != last_ignored_compare;
         prev = PREV_INSN (prev))
          {
        if (NOTE_P (prev))
          delete_insn (prev);    /* Use delete_note.  */
          }

        return prev;
      }

    /* If the template is the string "#", it means that this insn must
       be split.  */
    if (templ[0] == '#' && templ[1] == '\0')
      {
        rtx_insn *new_rtx = try_split (body, insn, 0);

        /* If we didn't split the insn, go away.  */
        if (new_rtx == insn && PATTERN (new_rtx) == body)
          fatal_insn ("could not split insn", insn);

        /* If we have a length attribute, this instruction should have
           been split in shorten_branches, to ensure that we would have
           valid length info for the splitees.  */
        gcc_assert (!HAVE_ATTR_length);

        return new_rtx;
      }

    /* ??? This will put the directives in the wrong place if
       get_insn_template outputs assembly directly.  However calling it
       before get_insn_template breaks if the insns is split.  */
    if (targetm.asm_out.unwind_emit_before_insn
        && targetm.asm_out.unwind_emit)
      targetm.asm_out.unwind_emit (asm_out_file, insn);

    rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn);
    if (call_insn != NULL)
      {
        rtx x = call_from_call_insn (call_insn);
        x = XEXP (x, 0);
        if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
          {
        tree t;
        x = XEXP (x, 0);
        t = SYMBOL_REF_DECL (x);
        if (t)
          assemble_external (t);
          }
      }

    /* Output assembler code from the template.  */
    output_asm_insn (templ, recog_data.operand);

    /* Some target machines need to postscan each insn after
       it is output.  */
    if (targetm.asm_out.final_postscan_insn)
      targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
                           recog_data.n_operands);

    if (!targetm.asm_out.unwind_emit_before_insn
        && targetm.asm_out.unwind_emit)
      targetm.asm_out.unwind_emit (asm_out_file, insn);

    /* Let the debug info back-end know about this call.  We do this only
       after the instruction has been emitted because labels that may be
       created to reference the call instruction must appear after it.  */
    if ((debug_variable_location_views || call_insn != NULL)
        && !DECL_IGNORED_P (current_function_decl))
      debug_hooks->var_location (insn);

    current_output_insn = debug_insn = 0;
      }
    }
  return NEXT_INSN (insn);
}

const char *
get_insn_template (int code, rtx_insn *insn)

{
  switch (insn_data[code].output_format)
    {
    case INSN_OUTPUT_FORMAT_SINGLE:
      return insn_data[code].output.single;
    case INSN_OUTPUT_FORMAT_MULTI:
      return insn_data[code].output.multi[which_alternative];
    case INSN_OUTPUT_FORMAT_FUNCTION:
      gcc_assert (insn);
      return (*insn_data[code].output.function) (recog_data.operand, insn);

    default:
      gcc_unreachable ();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoldKey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值