📄 final.c
字号:
/* The final scan for one insn, INSN. Args are same as in `final', except that INSN is the insn being scanned. Value returned is the next insn to be scanned. NOPEEPHOLES is the flag to disallow peephole processing (currently used for within delayed branch sequence output). */rtxfinal_scan_insn (insn, file, optimize, prescan, nopeepholes) rtx insn; FILE *file; int optimize; int prescan; int nopeepholes;{ register int i; insn_counter++; /* Ignore deleted insns. These can occur when we split insns (due to a template of "#") while not optimizing. */ if (INSN_DELETED_P (insn)) return NEXT_INSN (insn); switch (GET_CODE (insn)) { case NOTE: if (prescan > 0) break; /* Align the beginning of a loop, for higher speed on certain machines. */ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG && optimize > 0) {#ifdef ASM_OUTPUT_LOOP_ALIGN rtx next = next_nonnote_insn (insn); if (next && GET_CODE (next) == CODE_LABEL) { ASM_OUTPUT_LOOP_ALIGN (asm_out_file); }#endif break; } if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) break; if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END) {#ifdef FUNCTION_END_PROLOGUE FUNCTION_END_PROLOGUE (file);#endif profile_after_prologue (file); break; }#ifdef FUNCTION_BEGIN_EPILOGUE if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG) { FUNCTION_BEGIN_EPILOGUE (file); break; }#endif if (write_symbols == NO_DEBUG) break; if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) {#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) sdbout_begin_function (last_linenum);#endif#ifdef XCOFF_DEBUGGING_INFO if (write_symbols == XCOFF_DEBUG) xcoffout_begin_function (file, last_linenum);#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) dwarfout_begin_function ();#endif break; } if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) break; /* An insn that was "deleted" */ if (app_on) { fprintf (file, ASM_APP_OFF); app_on = 0; } if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG && (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE#ifdef DWARF_DEBUGGING_INFO || write_symbols == DWARF_DEBUG#endif ) ) { /* Beginning of a symbol-block. Assign it a sequence number and push the number onto the stack PENDING_BLOCKS. */ if (block_depth == max_block_depth) { /* PENDING_BLOCKS is full; make it longer. */ max_block_depth *= 2; pending_blocks = (int *) xrealloc (pending_blocks, max_block_depth * sizeof (int)); } pending_blocks[block_depth++] = next_block_index; /* Output debugging info about the symbol-block beginning. */#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) sdbout_begin_block (file, last_linenum, next_block_index);#endif#ifdef XCOFF_DEBUGGING_INFO if (write_symbols == XCOFF_DEBUG) xcoffout_begin_block (file, last_linenum, next_block_index);#endif#ifdef DBX_DEBUGGING_INFO if (write_symbols == DBX_DEBUG) ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG && block_depth > 1) dwarfout_begin_block (next_block_index);#endif next_block_index++; } else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END && (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE#ifdef DWARF_DEBUGGING_INFO || write_symbols == DWARF_DEBUG#endif ) ) { /* End of a symbol-block. Pop its sequence number off PENDING_BLOCKS and output debugging info based on that. */ --block_depth;#ifdef XCOFF_DEBUGGING_INFO if (write_symbols == XCOFF_DEBUG && block_depth >= 0) xcoffout_end_block (file, last_linenum, pending_blocks[block_depth]);#endif#ifdef DBX_DEBUGGING_INFO if (write_symbols == DBX_DEBUG && block_depth >= 0) ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", pending_blocks[block_depth]);#endif#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG && block_depth >= 0) sdbout_end_block (file, last_linenum);#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG && block_depth >= 1) dwarfout_end_block (pending_blocks[block_depth]);#endif } else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL && (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE)) {#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) dwarfout_label (insn);#endif } else if (NOTE_LINE_NUMBER (insn) > 0) /* This note is a line-number. */ { register rtx note;#if 0 /* This is what we used to do. */ output_source_line (file, insn);#endif int note_after = 0; /* If there is anything real after this note, output it. If another line note follows, omit this one. */ for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note)) { if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL) break; /* These types of notes can be significant so make sure the preceding line number stays. */ else if (GET_CODE (note) == NOTE && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG)) break; else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0) { /* Another line note follows; we can delete this note if no intervening line numbers have notes elsewhere. */ int num; for (num = NOTE_LINE_NUMBER (insn) + 1; num < NOTE_LINE_NUMBER (note); num++) if (line_note_exists[num]) break; if (num >= NOTE_LINE_NUMBER (note)) note_after = 1; break; } } /* Output this line note if it is the first or the last line note in a row. */ if (!note_after) output_source_line (file, insn); } break; case BARRIER:#ifdef ASM_OUTPUT_ALIGN_CODE /* Don't litter the assembler output with needless alignments. A BARRIER will be placed at the end of every function if HAVE_epilogue is true. */ if (NEXT_INSN (insn)) ASM_OUTPUT_ALIGN_CODE (file);#endif break; case CODE_LABEL: CC_STATUS_INIT; if (prescan > 0) break; new_block = 1;#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG && LABEL_NAME (insn)) sdbout_label (insn);#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn)) dwarfout_label (insn);#endif if (app_on) { fprintf (file, ASM_APP_OFF); app_on = 0; } if (NEXT_INSN (insn) != 0 && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) { rtx nextbody = PATTERN (NEXT_INSN (insn)); /* 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. */ if (GET_CODE (nextbody) == ADDR_VEC || GET_CODE (nextbody) == ADDR_DIFF_VEC) {#ifndef JUMP_TABLES_IN_TEXT_SECTION readonly_data_section ();#ifdef READONLY_DATA_SECTION ASM_OUTPUT_ALIGN (file, exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT));#endif /* READONLY_DATA_SECTION */#else /* JUMP_TABLES_IN_TEXT_SECTION */ text_section ();#endif /* JUMP_TABLES_IN_TEXT_SECTION */#ifdef ASM_OUTPUT_CASE_LABEL ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), NEXT_INSN (insn));#else ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));#endif break; } } ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); break; default: { register rtx body = PATTERN (insn); int insn_code_number; char *template; rtx note; /* 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;#ifdef HAVE_cc0 /* If there is a REG_CC_SETTER note on this insn, it means that the setting of the condition code was done in the delay slot of the insn that branched here. So recover the cc status from the insn that set it. */ note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); if (note) { NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); cc_prev_status = cc_status; }#endif /* Detect insns that are really jump-tables and output them as such. */ if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) { register int vlen, idx; if (prescan > 0) break; if (app_on) { fprintf (file, ASM_APP_OFF); app_on = 0; } 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 abort ();#endif } else {#ifdef ASM_OUTPUT_ADDR_DIFF_ELT ASM_OUTPUT_ADDR_DIFF_ELT (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));#else abort ();#endif } }#ifdef ASM_OUTPUT_CASE_END ASM_OUTPUT_CASE_END (file, CODE_LABEL_NUMBER (PREV_INSN (insn)), insn);#endif text_section (); break; } /* Do basic-block profiling when we reach a new block. Done here to avoid jump tables. */ if (profile_block_flag && new_block) { new_block = 0; /* Enable the table of basic-block use counts to point at the code it applies to. */ ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks); /* Before first insn of this basic block, increment the count of times it was entered. */#ifdef BLOCK_PROFILER BLOCK_PROFILER (file, count_basic_blocks); CC_STATUS_INIT;#endif count_basic_blocks++; } if (GET_CODE (body) == ASM_INPUT) { /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; if (prescan > 0) break; if (! app_on) { fprintf (file, ASM_APP_ON); app_on = 1; } fprintf (asm_out_file, "\t%s\n", XSTR (body, 0)); break; } /* Detect `asm' construct with operands. */ if (asm_noperands (body) >= 0) { int noperands = asm_noperands (body); rtx *ops; char *string; /* There's no telling what that did to the condition codes. */ CC_STATUS_INIT; if (prescan > 0) break; /* alloca won't do here, since only return from `final' would free it. */ if (noperands > 0) ops = (rtx *) xmalloc (noperands * sizeof (rtx)); if (! app_on) { fprintf (file, ASM_APP_ON); app_on = 1; } /* Get out the operand values. */ string = decode_asm_operands (body, ops, NULL_PTR, NULL_PTR, NULL_PTR); /* Inhibit aborts on what would otherwise be compiler bugs. */ insn_noperands = noperands; this_is_asm_operands = insn; /* Output the insn using them. */ output_asm_insn (string, ops); this_is_asm_operands = 0; if (noperands > 0) free (ops); break; } if (prescan <= 0 && app_on) { fprintf (file, ASM_APP_OFF); app_on = 0; } if (GET_CODE (body) == SEQUENCE) { /* A delayed-branch sequence */ register int i; rtx next; if (prescan > 0) break; final_sequence = body; /* 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 (XVECEXP (body, 0, 0), file, 0, prescan, 1); if (next != XVECEXP (body, 0, 1)) { final_sequence = 0; return next; } for (i = 1; i < XVECLEN (body, 0); i++) final_scan_insn (XVECEXP (body, 0, i), file, 0, prescan, 1);#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 (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) CC_STATUS_INIT; /* Following a conditional branch sequence, we have a new basic block. */ if (profile_block_flag) { rtx insn = XVECEXP (body, 0, 0); rtx body = PATTERN (insn); if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) != LABEL_REF) || (GET_CODE (insn) == JUMP_INSN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -