📄 final.c
字号:
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]); else if (GET_CODE (recog_operand[i]) == PLUS || GET_CODE (recog_operand[i]) == MULT) recog_operand[i] = walk_alter_subreg (recog_operand[i]); } for (i = 0; i < insn_n_dups[insn_code_number]; i++) { if (GET_CODE (*recog_dup_loc[i]) == SUBREG) *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]); else if (GET_CODE (*recog_dup_loc[i]) == PLUS || GET_CODE (*recog_dup_loc[i]) == MULT) *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[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;{ register char *filename = NOTE_SOURCE_FILE (insn); /* Remember filename for basic block profiling. Filenames are allocated on the permanent obstack or are passed in ARGV, so we don't have to save the string. */ if (profile_block_flag && last_filename != filename) bb_file_label_num = add_bb_string (filename, TRUE); last_filename = filename; last_linenum = NOTE_LINE_NUMBER (insn); high_block_linenum = MAX (last_linenum, high_block_linenum); high_function_linenum = MAX (last_linenum, high_function_linenum); 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) if (write_symbols == DBX_DEBUG) dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));#endif#if defined (XCOFF_DEBUGGING_INFO) if (write_symbols == XCOFF_DEBUG) xcoffout_source_line (file, filename, insn);#endif#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)))); 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); value = 2; break; case LTU: /* Jump becomes no-op. */ return -1; } if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N)) switch (GET_CODE (cond)) { case LE: case LEU: case GE: case GEU: case LT: case LTU: case GT: case GTU: abort (); case NE: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); value = 2; break; case EQ: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); value = 2; break; } if (cc_status.flags & CC_NOT_SIGNED) /* The flags are valid if signed condition operators are converted to unsigned. */ switch (GET_CODE (cond)) { case LE: PUT_CODE (cond, LEU); value = 2; break; case LT: PUT_CODE (cond, LTU); value = 2; break; case GT: PUT_CODE (cond, GTU); value = 2; break; case GE: PUT_CODE (cond, GEU); value = 2; break; } return value;}#endif/* Report inconsistency between the assembler template and the operands. In an `asm', it's the user's fault; otherwise, the compiler's fault. */voidoutput_operand_lossage (str) char *str;{ if (this_is_asm_operands) error_for_asm (this_is_asm_operands, "invalid `asm': %s", str); else abort ();}/* Output of assembler code from a template, and its subroutines. *//* Output text from TEMPLATE to the assembler output file, obeying %-directions to substitute operands taken from the vector OPERANDS. %N (for N a digit) means print operand N in usual manner. %lN means require operand N to be a CODE_LABEL or LABEL_REF and print the label name with no punctuation. %cN means require operand N to be a constant and print the constant expression with no punctuation. %aN means expect operand N to be a memory address (not a memory reference!) and print a reference to that address. %nN means expect operand N to be a constant and print a constant expression for minus the value of the operand, with no other punctuation. */static voidoutput_asm_name (){ if (flag_print_asm_name) { /* Annotate the assembly with a comment describing the pattern and alternative used. */ if (debug_insn) { register int num = INSN_CODE (debug_insn); fprintf (asm_out_file, " %s %d %s", ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]); if (insn_n_a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -