📄 final.c
字号:
FILE *file; rtx insn; enum debugger write_symbols;{ register char *filename = NOTE_SOURCE_FILE (insn); last_linenum = NOTE_LINE_NUMBER (insn); if (write_symbols == GDB_DEBUG) { /* Output GDB-format line number info. */ /* If this is not the same source file as last time, find or assign a GDB-file-number to this file. */ if (filename && (lastfile == 0 || strcmp (filename, lastfile) || current_gdbfile == 0)) set_current_gdbfile (filename); ++current_gdbfile->nlines; fprintf (file, "\t.gdbline %d,%d\n", current_gdbfile->filenum, NOTE_LINE_NUMBER (insn)); } if (write_symbols == SDB_DEBUG || write_symbols == DBX_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 ? last_linenum - sdb_begin_function_line : 1));#endif }#endif#ifdef DBX_DEBUGGING_INFO if (write_symbols == DBX_DEBUG) { /* Write DBX line number data. */ if (filename && (lastfile == 0 || strcmp (filename, lastfile))) {#ifdef ASM_OUTPUT_SOURCE_FILENAME ASM_OUTPUT_SOURCE_FILENAME (file, filename);#else fprintf (file, "\t.stabs \"%s\",%d,0,0,Ltext\n", filename, N_SOL);#endif lastfile = filename; } }#ifdef ASM_OUTPUT_SOURCE_LINE ASM_OUTPUT_SOURCE_LINE (file, NOTE_LINE_NUMBER (insn));#else fprintf (file, "\t.stabd %d,0,%d\n", N_SLINE, NOTE_LINE_NUMBER (insn));#endif#endif /* DBX_DEBUGGING_INFO */ }}/* 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;#ifdef 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); } else if (GET_CODE (y) == CONST_DOUBLE) return y; 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;}/* 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; switch (GET_CODE (cond)) { case LE: PUT_CODE (cond, GE); break; case GE: PUT_CODE (cond, LE); break; case LT: PUT_CODE (cond, GT); break; case GT: PUT_CODE (cond, LT); break; case LEU: PUT_CODE (cond, GEU); break; case GEU: PUT_CODE (cond, LEU); break; case LTU: PUT_CODE (cond, GTU); break; case GTU: PUT_CODE (cond, LTU); break; } } 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; } return value;}/* Report inconsistency between the assembler template and the operands. In an `asm', it's the user's fault; otherwise, the compiler's fault. */static 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. */voidoutput_asm_insn (template, operands) char *template; rtx *operands;{ register char *p; register int c; /* An insn may return a null string template in a case where no assembler code is needed. */ if (*template == 0) return; p = template; putc ('\t', asm_out_file);#ifdef ASM_OUTPUT_OPCODE ASM_OUTPUT_OPCODE (asm_out_file, p);#endif while (c = *p++) {#ifdef ASM_OUTPUT_OPCODE if (c == '\n') { putc (c, asm_out_file); while ((c = *p) == '\t') { putc (c, asm_out_file); p++; } ASM_OUTPUT_OPCODE (asm_out_file, p); } else#endif if (c != '%') putc (c, asm_out_file); else { /* %% outputs a single %. */ if (*p == '%') { p++; putc (c, asm_out_file); } /* % followed by a letter and some digits outputs an operand in a special way depending on the letter. Letters `acln' are implemented here. Other letters are passed to `output_operand' so that the PRINT_OPERAND macro can define them. */ else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) { int letter = *p++; c = atoi (p); if (! (*p >= '0' && *p <= '9')) output_operand_lossage ("operand number missing after %-letter"); else if (this_is_asm_operands && c >= (unsigned) insn_noperands) output_operand_lossage ("operand number out of range"); else if (letter == 'l') output_asm_label (operands[c]); else if (letter == 'a') output_address (operands[c]); else if (letter == 'c') { if (CONSTANT_ADDRESS_P (operands[c])) output_addr_const (asm_out_file, operands[c]); else output_operand (operands[c], 'c'); } else if (letter == 'n') { if (GET_CODE (operands[c]) == CONST_INT) fprintf (asm_out_file, "%d", - INTVAL (operands[c])); else { putc ('-', asm_out_file); output_addr_const (asm_out_file, operands[c]); } } else output_operand (operands[c], letter); while ((c = *p) >= '0' && c <= '9') p++; } /* % followed by a digit outputs an operand the default way. */ else if (*p >= '0' && *p <= '9') { c = atoi (p); if (this_is_asm_operands && c >= (unsigned) insn_noperands) output_operand_lossage ("operand number out of range"); else output_operand (operands[c], 0); while ((c = *p) >= '0' && c <= '9') p++; } /* % followed by punctuation: output something for that punctuation character alone, with no operand. The PRINT_OPERAND macro decides what is actually done. */#ifdef PRINT_OPERAND_PUNCT_VALID_P else if (PRINT_OPERAND_PUNCT_VALID_P (*p)) output_operand (0, *p++);#endif else output_operand_lossage ("invalid %%-code"); } } putc ('\n', asm_out_file);}/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */voidoutput_asm_label (x) rtx x;{ char buf[256]; if (GET_CODE (x) == LABEL_REF) ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); else if (GET_CODE (x) == CODE_LABEL) ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); else output_operand_lossage ("`%l' operand isn't a label"); assemble_name (asm_out_file, buf);}/* Print operand X using machine-dependent assembler syntax. The macro PRINT_OPERAND is defined just to control this function. CODE is a non-digit that preceded the operand-number in the % spec, such as 'z' if the spec was `%z3'. CODE is 0 if there was no char between the % and the digits. When CODE is a non-letter, X is 0. The meanings of the letters are machine-dependent and controlled by PRINT_OPERAND. */static voidoutput_operand (x, code) rtx x; int code;{ if (x && GET_CODE (x) == SUBREG) x = alter_subreg (x); PRINT_OPERAND (asm_out_file, x, code);}/* Print a memory reference operand for address X using machine-dependent assembler syntax. The macro PRINT_OPERAND_ADDRESS exists just to control this function. */voidoutput_address (x) rtx x;{ walk_alter_subreg (x); PRINT_OPERAND_ADDRESS (asm_out_file, x);}/* Print an integer constant expression in assembler syntax. Addition and subtraction are the only arithmetic that may appear in these expressions. */voidoutput_addr_const (file, x) FILE *file; rtx x;{ char buf[256]; restart: switch (GET_CODE (x)) { case SYMBOL_REF: assemble_name (file, XSTR (x, 0)); break; case LABEL_REF: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); assemble_name (asm_out_file, buf); break; case CODE_LABEL: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); assemble_name (asm_out_file, buf); break; case CONST_INT: fprintf (file, "%d", INTVAL (x)); break; case CONST: x = XEXP (x, 0); goto restart; case CONST_DOUBLE: if (GET_MODE (x) == DImode) { /* We can use %d if the number is <32 bits and positive. */ if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0) fprintf (file, "0x%x%08x", CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); else fprintf (file, "%d", CONST_DOUBLE_LOW (x)); } else /* We can't handle floating point constants; PRINT_OPERAND must handle them. */ output_operand_lossage ("floating constant misused"); break; case PLUS: /* Some assemblers need integer constants to appear last (eg masm). */ if (GET_CODE (XEXP (x, 0)) == CONST_INT) { output_addr_const (file, XEXP (x, 1)); if (INTVAL (XEXP (x, 0)) >= 0) fprintf (file, "+"); output_addr_const (file, XEXP (x, 0)); } else { output_addr_const (file, XEXP (x, 0)); if (INTVAL (XEXP (x, 1)) >= 0) fprintf (file, "+"); output_addr_const (file, XEXP (x, 1)); } break; case MINUS: output_addr_const (file, XEXP (x, 0)); fprintf (file, "-"); output_addr_const (file, XEXP (x, 1)); break; default: output_operand_lossage ("invalid expression as operand"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -