当前位置: 首页 > news >正文

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 ();
}
}

http://www.dtcms.com/a/286591.html

相关文章:

  • C++ 程序 AddressSanitizer:DEADLYSIGNAL
  • 自动化面试题
  • spring-cloud微服务部署转单体部署-feign直连调用
  • 磁悬浮轴承系统中由不平衡力引发的恶性循环机制深度解析
  • 初探:C语言FILE结构之文件描述符与缓冲区的实现原理
  • 前端 SSE 实战应用:用最简单的方式实现实时推送
  • Python基础④-装饰器、迭代器及常用函数篇
  • 在断网情况下,网线直接连接 Windows 笔记本和 Ubuntu 服务器进行数据传输
  • 高性能数据库-Redis详解
  • verilog tb文件 美化terminal输出
  • Webpack 项目构建优化详解
  • 雪豹大模型驱动效率革命 华鼎冷链科技重构餐饮供应链神经网络
  • 进程 线程 并发 并行
  • 安达发|从救火到未雨绸缪:APS生产计划排产软件重塑制造业“危机免疫力“
  • 2025年6月电子学会全国青少年软件编程等级考试(Python一级)真题及答案
  • 添加DNS解析记录时,提醒记录冲突是怎么回事?
  • Python练习2-格式化输出基本数据类型及变量的详细使用
  • Aqara 携手西门子西碳迹SiTANJI,发布亚马逊 CPF 绿标解决方案标杆案例
  • 根据用户id自动切换表查询
  • c语言笔记---结构体
  • 浏览器元素定位工具-项目源码免费领取
  • 萤石摄像头C++SDK应用实例
  • 前端笔记之 async/await 异步编程详解
  • 面试高频题 力扣 695.岛屿的最大面积 洪水灌溉(FloodFill) 深度优先遍历 暴力搜索 C++解题思路 每日一题
  • Python网络爬虫之selenium库
  • 第九章 基础设施更新工程
  • 语音控制操作板:人机交互的未来趋势
  • 企业级异常处理方案:Spring Boot自定义异常全局拦截实战
  • 多线程的认识
  • 深入Java注解:从内置到元注解与自定义实战指南