📄 final.c
字号:
&& 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 /* 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)); if (result == 1) validate_change (insn, &SET_SRC (body), const_true_rtx, 0); else if (result == -1) validate_change (insn, &SET_SRC (body), const0_rtx, 0); else if (result == 2) INSN_CODE (insn) = -1; } } }#endif /* 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 prev = PREV_INSN (insn); rtx note; for (note = NEXT_INSN (insn); note != next; note = NEXT_INSN (note)) final_scan_insn (note, file, optimize, prescan, nopeepholes); /* 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, 1)) fatal_insn_not_found (insn);#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#ifdef HAVE_cc0 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);#endif debug_insn = 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_nonnote_insn (insn) != last_ignored_compare) abort (); new_block = 0; return prev_nonnote_insn (insn); } } /* If the template is the string "#", it means that this insn must be split. */ if (template[0] == '#' && template[1] == '\0') { rtx new = try_split (body, insn, 0); /* If we didn't split the insn, go away. */ if (new == insn && PATTERN (new) == body) abort (); new_block = 0; return new; } if (prescan > 0) break; /* Output assembler code from the template. */ output_asm_insn (template, recog_operand);#if 0 /* It's not at all clear why we did this and doing so interferes with tests we'd like to do to use REG_WAS_0 notes, so let's try with this out. */ /* Mark this insn as having been output. */ INSN_DELETED_P (insn) = 1;#endif debug_insn = 0; } } return NEXT_INSN (insn);}/* 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) FILE *file; rtx insn;{ char ltext_label_name[100]; register char *filename = NOTE_SOURCE_FILE (insn); last_linenum = NOTE_LINE_NUMBER (insn); if (write_symbols != NO_DEBUG) {#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG#if 0 /* People like having line numbers even in wrong file! */ /* COFF can't handle multiple source files--lose, lose. */ && !strcmp (filename, main_input_filename)#endif /* COFF relative line numbers must be positive. */ && last_linenum > sdb_begin_function_line) {#ifdef ASM_OUTPUT_SOURCE_LINE ASM_OUTPUT_SOURCE_LINE (file, last_linenum);#else fprintf (file, "\t.ln\t%d\n", ((sdb_begin_function_line > -1) ? last_linenum - sdb_begin_function_line : 1));#endif }#endif#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) dwarfout_line (filename, NOTE_LINE_NUMBER (insn));#endif }}/* If X is a SUBREG, replace it with a REG or a MEM, based on the thing it is a subreg of. */rtxalter_subreg (x) register rtx x;{ register rtx y = SUBREG_REG (x); if (GET_CODE (y) == SUBREG) y = alter_subreg (y); if (GET_CODE (y) == REG) { /* If the containing reg really gets a hard reg, so do we. */ PUT_CODE (x, REG); REGNO (x) = REGNO (y) + SUBREG_WORD (x); } else if (GET_CODE (y) == MEM) { register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;#if BYTES_BIG_ENDIAN offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));#endif PUT_CODE (x, MEM); MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y); XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); } return x;}/* Do alter_subreg on all the SUBREGs contained in X. */static rtxwalk_alter_subreg (x) rtx x;{ switch (GET_CODE (x)) { case PLUS: case MULT: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1)); break; case MEM: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); break; case SUBREG: return alter_subreg (x); } return x;}#ifdef HAVE_cc0/* Given BODY, the body of a jump instruction, alter the jump condition as required by the bits that are set in cc_status.flags. Not all of the bits there can be handled at this level in all cases. The value is normally 0. 1 means that the condition has become always true. -1 means that the condition has become always false. 2 means that COND has been altered. */static intalter_cond (cond) register rtx cond;{ int value = 0; if (cc_status.flags & CC_REVERSED) { value = 2; PUT_CODE (cond, swap_condition (GET_CODE (cond))); } if (cc_status.flags & CC_INVERTED) { value = 2; PUT_CODE (cond, reverse_condition (GET_CODE (cond))); } if (cc_status.flags & CC_NOT_POSITIVE) switch (GET_CODE (cond)) { case LE: case LEU: case GEU: /* Jump becomes unconditional. */ return 1; case GT: case GTU: case LTU: /* Jump becomes no-op. */ return -1; case GE: PUT_CODE (cond, EQ); value = 2; break; case LT: PUT_CODE (cond, NE); value = 2; break; } if (cc_status.flags & CC_NOT_NEGATIVE) switch (GET_CODE (cond)) { case GE: case GEU: /* Jump becomes unconditional. */ return 1; case LT: case LTU: /* Jump becomes no-op. */ return -1; case LE: case LEU: PUT_CODE (cond, EQ); value = 2; break; case GT: case GTU: PUT_CODE (cond, NE); value = 2; break; } if (cc_status.flags & CC_NO_OVERFLOW) switch (GET_CODE (cond)) { case GEU: /* Jump becomes unconditional. */ return 1; case LEU: PUT_CODE (cond, EQ); value = 2; break; case GTU: PUT_CODE (cond, NE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -