📄 final.c
字号:
int optimize; int prescan;{ register rtx insn; last_ignored_compare = 0; new_block = 1; init_recog (); CC_STATUS_INIT; for (insn = NEXT_INSN (first); insn;) insn = final_scan_insn (insn, file, write_symbols, optimize, prescan, 0);}/* 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, write_symbols, optimize, prescan, nopeepholes) rtx insn; FILE *file; enum debugger write_symbols; int optimize; int prescan; int nopeepholes;{ register int i; switch (GET_CODE (insn)) { case NOTE: if (prescan > 0) break; 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 break; } if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) 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) { /* 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 DBX_DEBUGGING_INFO if (write_symbols == DBX_DEBUG) ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);#endif if (write_symbols == GDB_DEBUG) fprintf (file, "\t.gdbbeg %d\n", next_block_index); next_block_index++; } else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) { /* End of a symbol-block. Pop its sequence number off PENDING_BLOCKS and output debugging info based on that. */ --block_depth;#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 if (write_symbols == GDB_DEBUG) fprintf (file, "\t.gdbend %d\n", pending_blocks[block_depth]); } else if (NOTE_LINE_NUMBER (insn) > 0) /* This note is a line-number. */ output_source_line (file, insn, write_symbols); break; case BARRIER:#ifdef ASM_OUTPUT_ALIGN_CODE ASM_OUTPUT_ALIGN_CODE (file);#endif break; case CODE_LABEL: CC_STATUS_INIT; if (prescan > 0) break; new_block = 1; if (app_on) { fprintf (file, ASM_APP_OFF); app_on = 0; }#ifdef ASM_OUTPUT_CASE_LABEL 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, output the two of them together in a special way. */ if (GET_CODE (nextbody) == ADDR_VEC || GET_CODE (nextbody) == ADDR_DIFF_VEC) { ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), NEXT_INSN (insn)); break; } }#endif ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); break; default: { register rtx body = PATTERN (insn); int insn_code_number; char *template; /* 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; if (profile_block_flag && new_block) { rtx real_body = body; if (GET_CODE (insn) == NOTE) real_body = PATTERN (next_real_insn (insn)); /* Don't add instructions in front of jump tables. */ if (GET_CODE (real_body) != ADDR_VEC && GET_CODE (real_body) != ADDR_DIFF_VEC) { 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);#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, 0, 0, 0); /* 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; } /* Detect insns that are really jump-tables and output them as such. */ if (GET_CODE (body) == ADDR_VEC) { register int vlen, idx; if (prescan > 0) break; vlen = XVECLEN (body, 0); for (idx = 0; idx < vlen; idx++) ASM_OUTPUT_ADDR_VEC_ELT (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));#ifdef ASM_OUTPUT_CASE_END ASM_OUTPUT_CASE_END (file, CODE_LABEL_NUMBER (PREV_INSN (insn)), insn);#endif break; } if (GET_CODE (body) == ADDR_DIFF_VEC) { register int vlen, idx; if (prescan > 0) break; vlen = XVECLEN (body, 1); for (idx = 0; idx < vlen; idx++) ASM_OUTPUT_ADDR_DIFF_ELT (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));#ifdef ASM_OUTPUT_CASE_END ASM_OUTPUT_CASE_END (file, CODE_LABEL_NUMBER (PREV_INSN (insn)), insn);#endif break; } if (recog_memoized (insn) == -1 && GET_CODE (body) == SEQUENCE) /* A delayed-branch sequence */ { register int i; if (prescan > 0) break; final_sequence = body; for (i = 0; i < XVECLEN (body, 0); i++) final_scan_insn (XVECEXP (body, 0, i), file, write_symbols, optimize, prescan, 1); final_sequence = 0;#ifdef DBR_OUTPUT_SEQEND DBR_OUTPUT_SEQEND (file);#endif break; } /* We have a real machine instruction as rtl. */ body = PATTERN (insn); /* 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)); 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 has an addressing side-effect */ if (! find_reg_note (insn, REG_INC, 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; } } } /* Following a conditional branch, we have a new basic block. */ if (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) != LABEL_REF) new_block = 1; /* 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 /* 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; } /* Rerecognize the instruction if it has changed. */ if (result != 0) INSN_CODE (insn) = -1; }#ifdef STORE_FLAG_VALUE /* 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 (GET_CODE (XEXP (SET_SRC (body), 0)) != CC0) break; result = alter_cond (SET_SRC (body)); if (result == 1) SET_SRC (body) = gen_rtx (CONST_INT, VOIDmode, STORE_FLAG_VALUE); if (result == -1) SET_SRC (body) = const0_rtx; if (result != 0) INSN_CODE (insn) = -1; } }#endif /* STORE_FLAG_VALUE */ /* Do machine-specific peephole optimizations if desired. */ if (optimize && !flag_no_peephole && !nopeepholes) { rtx 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 note = NEXT_INSN (insn); rtx prev = PREV_INSN (insn); while (note != next) { final_scan_insn (note, file, write_symbols, optimize, prescan, nopeepholes); note = NEXT_INSN (note); } /* In case this is prescan, put the notes in proper position for later rescan. */ note = NEXT_INSN (insn); PREV_INSN (note) = prev; NEXT_INSN (prev) = note; NEXT_INSN (PREV_INSN (next)) = insn; PREV_INSN (insn) = PREV_INSN (next); NEXT_INSN (insn) = next; 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); insn_extract (insn); for (i = 0; i < insn_n_operands[insn_code_number]; i++) { if (GET_CODE (recog_operand[i]) == SUBREG) recog_operand[i] = alter_subreg (recog_operand[i]); }#ifdef REGISTER_CONSTRAINTS if (! constrain_operands (insn_code_number)) abort ();#endif /* Some target machines need to prescan each insn before it is output. */#ifdef FINAL_PRESCAN_INSN FINAL_PRESCAN_INSN (insn, recog_operand, insn_n_operands[insn_code_number]);#endif cc_prev_status = cc_status; /* Update `cc_status' for this instruction. The instruction's output routine may change it further. If the output routine for a jump insn needs to depend on the cc status, it should look at cc_prev_status. */ NOTICE_UPDATE_CC (body, insn); /* If the proper template needs to be chosen by some C code, run that code and get the real template. */ template = insn_template[insn_code_number]; if (template == 0) { template = (*insn_outfun[insn_code_number]) (recog_operand, 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 (template == 0) { if (PREV_INSN (insn) != last_ignored_compare) abort (); new_block = 0; return PREV_INSN (insn); } } if (prescan > 0) break; /* Output assembler code from the template. */ output_asm_insn (template, recog_operand); /* Mark this insn as having been output. */ INSN_DELETED_P (insn) = 1; } } return NEXT_INSN (insn);}/* Set up FILENAME as the current file for GDB line-number output. */voidset_current_gdbfile (filename) char *filename;{ register struct gdbfile *f; for (f = gdbfiles; f; f = f->next) if (!strcmp (f->name, filename)) break; if (!f) { f = (struct gdbfile *) permalloc (sizeof (struct gdbfile)); f->next = gdbfiles; gdbfiles = f; f->name = filename; f->filenum = next_gdb_filenum++; f->nlines = 0; } current_gdbfile = f; lastfile = filename;}/* Output debugging info to the assembler file FILE based on the NOTE-insn INSN, assumed to be a line number. */static voidoutput_source_line (file, insn, write_symbols)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -