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.pswp.cn/web/90080.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90080.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90080.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STC89C52系列單片機內部結構詳解

STC89C52 是基于 MCS-51 內核的增強型單片機&#xff0c;其內部結構集成了多種功能模塊&#xff0c;具備強大的數據處理和控制能力&#xff0c;是嵌入式系統中常用的一種微控制器。本文將結合內部結構框圖&#xff0c;詳細介紹 STC89C52 的各個核心組成部分及其功能作用。一、中…

Linux防火墻管理和基礎服務(FTP/SFTP)

防火墻管理# 開放端口firewalld-cmd --add-port880/tcp --permanent# 移除端口或阻止端口firewalld-cmd --remove-port880/tcp --permanent# 重啟服務systemctl restart firewalld# 查看防火墻開放哪些端口&#xff08;查看當前區域的規則&#xff09;firewall-cmd --lis…

Selenium+Java 自動化測試入門到實踐:從環境搭建到元素操作

在自動化測試領域&#xff0c;Selenium 憑借其強大的跨瀏覽器兼容性和靈活的 API&#xff0c;成為 Web 應用測試的首選工具。而 Java 作為一門穩定且廣泛應用的編程語言&#xff0c;與 Selenium 結合能構建出高效、可維護的自動化測試框架。本文將從環境搭建開始&#xff0c;逐…

Hugging Face 模型的緩存和直接下載有什么區別?

Hugging Face 模型的緩存和直接下載&#xff08;下載到本地文件夾&#xff09;是兩種不同的模型管理方式&#xff0c;它們在使用場景、存儲結構和效率上各有優劣。 以下是它們之間的主要區別&#xff1a; Hugging Face 緩存 (Cache) 當您通過 transformers 庫中的 from_pretrai…

JavaScript AJAX 實現,演示如何將 Token 添加到 Authorization

以下是一個完整的原生 JavaScript AJAX 實現&#xff0c;演示如何將 Token 添加到 Authorization 頭部的示例&#xff1a;基礎實現html復制代碼<!DOCTYPE html> <html> <head><title>AJAX Token 示例</title><script>// 獲取當前用戶的 To…

開發語言的優劣勢對比及主要應用領域分析

開發語言是程序員用來編寫軟件指令的工具。每種語言都有自己的設計哲學、語法&#xff08;規則&#xff09;和應用場景&#xff0c;但沒有“放之四海而皆準”的最佳語言。以下是主流和重要開發語言的介紹&#xff0c;按主要應用領域分類&#xff1a; 一、全能型語言 (可在多個領…

Java學習-------事務失效

在 Java 開發中&#xff0c;事務是保證數據一致性和完整性的關鍵機制&#xff0c;尤其在涉及多步數據庫操作的業務場景中不可或缺。然而&#xff0c;在實際開發過程中&#xff0c;事務常常會出現 “失效” 的情況 —— 預期的回滾沒有發生&#xff0c;數據出現不一致。 Java 事…

JavaScript 01 JavaScript 是什么

1.1 JavaScript 是什么JavaScript 是一門世界上最流行的腳本語言&#xff08;基本所有平臺的所有軟件都會用到它&#xff09;。“1994年&#xff0c;網景公司(Netscape)發布了Navigator瀏覽器0.9版。這是歷史上第一個比較成熟的網絡瀏覽器&#xff0c;轟動一時。但是&#xff0…

Bun v1.2.19發布,node_modules隔離,sql比node快6倍

大家好,我是農村程序員,獨立開發者,行業觀察員,前端之虎陳隨易。我會在這里分享關于 獨立開發、編程技術、思考感悟 等內容,歡迎關注。 技術群與交朋友請在個人網站聯系我,網站 1??:https://chensuiyi.me,網站 2??:https://me.yicode.tech。 如果你覺得本文有用…

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - 主頁布局實現

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解主頁布局實現 視頻在線地址&#xff1a; …

# 微調需要準備哪些環境配置?

微調需要準備哪些環境配置&#xff1f; 如果沒有 GPU&#xff0c;即便是微調較小的大語言模型&#xff08;LLMs&#xff09;&#xff0c;過程也會比較慢。如果你已經有了現成的 GPU&#xff0c;那就可以直接開工了。不過&#xff0c;并不是所有人都能負擔得起 GPU—— 這種情況…

ClickHouse物化視圖避坑指南:原理、數據遷移與優化

摘要ClickHouse物化視圖通過預計算和自動更新機制&#xff0c;顯著提升大數據分析查詢性能&#xff0c;尤其適合高并發聚合場景。本文將深入解析其技術原理、生產實踐中的優化策略&#xff0c;以及數據遷移的實戰經驗。一、物化視圖核心概念ClickHouse的物化視圖(Materialized …

Springboot3整合Elasticsearch8(elasticsearch-java)

1、Elasticsearch的JAVA客戶端選擇 Elasticsearch官方支持的客戶端 客戶端名稱簡介使用建議Elasticsearch Java API Client&#xff08;新客戶端&#xff09;官方推薦的新客戶端&#xff0c;基于 JSON Mapping&#xff08;如 ElasticsearchClient 類&#xff09;&#xff0c;…

OpenCV 官翻8 - 其他算法

文章目錄高動態范圍成像引言曝光序列源代碼示例圖像說明結果色調映射圖像曝光融合附加資源高級圖像拼接 API&#xff08;Stitcher 類&#xff09;目標代碼說明相機模型試用指南圖像拼接詳解 (Python OpenCV >4.0.1)stitching_detailed如何使用背景減除方法目標代碼代碼解析結…

2025年一區SCI-回旋鏢氣動橢圓優化算法Boomerang Aerodynamic Ellipse-附Matlab免費代碼

引言 本期介紹一種新的元啟發式算法——回旋鏢氣動橢圓優化算法Boomerang Aerodynamic Ellipse Optimizer (BAEO)。該優化器的靈感來自于飛行中的回旋鏢的空氣動力學行為&#xff0c;明確地建模了釋放角和發射力如何塑造其軌跡。于2025年7月最新發表在JCR 1區&#xff0c;中科…

Custom SRP - Custom Render Pipeline

https://catlikecoding.com/unity/tutorials/custom-srp/custom-render-pipeline/ 1. 新建 Render Pipeline 任何內容的渲染&#xff0c;最終都是要由 unity 決定在哪里&#xff0c;什么時候&#xff0c;以哪些參數進行渲染。根據目標效果的復雜程度&#xff0c;決定渲染的過程…

C語言面向對象編程

1.內核通用鏈表一、什么是 list_head&#xff1f;list_head 是 Linux 內核中自己實現的一種 雙向循環鏈表 的結構&#xff0c;定義在 <linux/list.h> 中。它設計得非常輕巧、靈活&#xff0c;廣泛用于內核模塊、驅動、進程調度、網絡協議棧等。它的關鍵思想是&#xff1a…

Spring Boot+Redis Zset:三步構建高可靠延遲隊列系統

系統設計架構圖---------------- ----------------- ---------------- | | | | | | | 生產者 |------>| Redis ZSet |------>| 定時任務消費者 | | (添加延遲任務) | | (延…

MCP vs 傳統集成方案:REST API、GraphQL、gRPC的終極對比

MCP vs 傳統集成方案&#xff1a;REST API、GraphQL、gRPC的終極對比 &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般絢爛的技術棧中&#xff0c;我是那個永不停歇的色彩收集者。 &#x1f98b; 每一個優化都是我培育的花朵&#xff0c;每一個特…

SQL語句中鎖的使用與優化

一、鎖機制簡介1.定義在數據庫中&#xff0c;除了傳統的計算資源&#xff08;如CPU、RAM、I/O等&#xff09;的爭用以外&#xff0c;數據也是一種供需要用戶共享的資源。如何保證數據并發訪問的一致性、有效性是所有數據庫必須解決的一個問題&#xff0c;鎖沖突也是影響數據庫并…