📄 final.c
字号:
sdbout_end_block (file, high_block_linenum, pending_blocks[block_depth]);#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 */ function_section (current_function_decl);#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 function_section (current_function_decl); break; } /* Do basic-block profiling when we reach a new block. Done here to avoid jump tables. */ if (profile_block_flag && new_block) add_bb (file); 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 = (rtx *) alloca (noperands * sizeof (rtx)); char *string; /* 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; } /* 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; 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++) { rtx insn = XVECEXP (body, 0, i); rtx next = NEXT_INSN (insn); /* We loop in case any instruction in a delay slot gets split. */ do insn = final_scan_insn (insn, file, 0, prescan, 1); 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 (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 && GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == SET && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)) new_block = 1; } break; } /* We have a real machine instruction as rtl. */ body = PATTERN (insn);#ifdef HAVE_cc0 /* Check for redundant test and compare instructions (when the condition codes are already set up as desired). This is done only when optimizing; if not optimizing, it should be possible for the user to alter a variable with the debugger in between statements and the next statement should reexamine the variable to compute the condition codes. */ if (optimize && GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == CC0 && insn != last_ignored_compare) { if (GET_CODE (SET_SRC (body)) == SUBREG) SET_SRC (body) = alter_subreg (SET_SRC (body)); else if (GET_CODE (SET_SRC (body)) == COMPARE) { if (GET_CODE (XEXP (SET_SRC (body), 0)) == SUBREG) XEXP (SET_SRC (body), 0) = alter_subreg (XEXP (SET_SRC (body), 0)); if (GET_CODE (XEXP (SET_SRC (body), 1)) == SUBREG) XEXP (SET_SRC (body), 1) = alter_subreg (XEXP (SET_SRC (body), 1)); } if ((cc_status.value1 != 0 && rtx_equal_p (SET_SRC (body), cc_status.value1)) || (cc_status.value2 != 0 && rtx_equal_p (SET_SRC (body), cc_status.value2))) { /* Don't delete insn if it has an addressing side-effect. */ if (! FIND_REG_INC_NOTE (insn, 0) /* or if anything in it is volatile. */ && ! volatile_refs_p (PATTERN (insn))) { /* We don't really delete the insn; just ignore it. */ last_ignored_compare = insn; break; } } }#endif /* Following a conditional branch, we have a new basic block. But if we are inside a sequence, the new block starts after the last insn of the sequence. */ if (profile_block_flag && final_sequence == 0 && ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) != LABEL_REF) || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == SET && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))) new_block = 1;#ifndef STACK_REGS /* Don't bother outputting obvious no-ops, even without -O. This optimization is fast and doesn't interfere with debugging. Don't do this if the insn is in a delay slot, since this will cause an improper number of delay insns to be written. */ if (final_sequence == 0 && prescan >= 0 && GET_CODE (insn) == INSN && GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == REG && GET_CODE (SET_DEST (body)) == REG && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) break;#endif#ifdef HAVE_cc0 /* If this is a conditional branch, maybe modify it if the cc's are in a nonstandard state so that it accomplishes the same thing that it would do straightforwardly if the cc's were set up normally. */ if (cc_status.flags != 0 && GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET && SET_DEST (body) == pc_rtx && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx /* This is done during prescan; it is not done again in final scan when prescan has been done. */ && prescan >= 0) { /* This function may alter the contents of its argument and clear some of the cc_status.flags bits. It may also return 1 meaning condition now always true or -1 meaning condition now always false or 2 meaning condition nontrivial but altered. */ register int result = alter_cond (XEXP (SET_SRC (body), 0)); /* If condition now has fixed value, replace the IF_THEN_ELSE with its then-operand or its else-operand. */ if (result == 1) SET_SRC (body) = XEXP (SET_SRC (body), 1); if (result == -1) SET_SRC (body) = XEXP (SET_SRC (body), 2); /* The jump is now either unconditional or a no-op. If it has become a no-op, don't try to output it. (It would not be recognized.) */ if (SET_SRC (body) == pc_rtx) { PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; break; } else if (GET_CODE (SET_SRC (body)) == RETURN) /* Replace (set (pc) (return)) with (return). */ PATTERN (insn) = body = SET_SRC (body); /* Rerecognize the instruction if it has changed. */ if (result != 0) INSN_CODE (insn) = -1; } /* Make same adjustments to instructions that examine the condition codes without jumping (if this machine has them). */ if (cc_status.flags != 0 && GET_CODE (body) == SET) { switch (GET_CODE (SET_SRC (body))) { case GTU: case GT: case LTU: case LT: case GEU: case GE: case LEU: case LE: case EQ: case NE: { register int result; if (XEXP (SET_SRC (body), 0) != cc0_rtx) break; result = alter_cond (SET_SRC (body));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -