📄 final.c
字号:
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. */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); } /* %= outputs a number which is unique to each insn in the entire compilation. This is useful for making local labels that are referred to more than once in a given insn. */ else if (*p == '=') { p++; fprintf (asm_out_file, "%d", insn_counter); } /* % followed by a letter and some digits outputs an operand in a special way depending on the letter. Letters `acln' are implemented directly. 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,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "%d",#else "%ld",#endif - 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 (NULL_RTX, *p++);#endif else output_operand_lossage ("invalid %%-code"); } } 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_alternatives[num] > 1) fprintf (asm_out_file, "/%d", which_alternative + 1); /* Clear this so only the first assembler insn of any rtl insn will get the special comment for -dp. */ debug_insn = 0; } } 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); /* If X is a pseudo-register, abort now rather than writing trash to the assembler file. */ if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) abort (); 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 PC: if (flag_pic) putc ('.', file); else abort (); break; 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 (file, buf); break; case CODE_LABEL: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); assemble_name (file, buf); break; case CONST_INT: fprintf (file,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "%d",#else "%ld",#endif INTVAL (x)); break; case CONST: /* This used to output parentheses around the expression, but that does not work on the 386 (either ATT or BSD assembler). */ output_addr_const (file, XEXP (x, 0)); break; case CONST_DOUBLE: if (GET_MODE (x) == VOIDmode) { /* We can use %d if the number is one word and positive. */ if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0) fprintf (file,#if HOST_BITS_PER_WIDE_INT == 64#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT " 0x%lx%016lx",#else " 0x%x%016x",#endif#else#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT " 0x%lx%08lx",#else " 0x%x%08x",#endif#endif CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); else fprintf (file,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "%d",#else "%ld",#endif 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: /* Avoid outputting things like x-x or x+5-x, since some assemblers can't handle that. */ x = simplify_subtraction (x); if (GET_CODE (x) != MINUS) goto restart; output_addr_const (file, XEXP (x, 0)); fprintf (file, "-"); if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) < 0) { fprintf (file, ASM_OPEN_PAREN); output_addr_const (file, XEXP (x, 1)); fprintf (file, ASM_CLOSE_PAREN); } else output_addr_const (file, XEXP (x, 1)); break; case ZERO_EXTEND: case SIGN_EXTEND: output_addr_const (file, XEXP (x, 0)); break; default: output_operand_lossage ("invalid expression as operand"); }}/* A poor man's fprintf, with the added features of %I, %R, %L, and %U. %R prints the value of REGISTER_PREFIX. %L prints the value of LOCAL_LABEL_PREFIX. %U prints the value of USER_LABEL_PREFIX. %I prints the value of IMMEDIATE_PREFIX. %O runs ASM_OUTPUT_OPCODE to transform what follows in the string. Also supported are %d, %x, %s, %e, %f, %g and %%. */voidasm_fprintf (va_alist) va_dcl{ va_list argptr; FILE *file; char buf[10]; char *p, *q, c; va_start (argptr); file = va_arg (argptr, FILE *); p = va_arg (argptr, char *); buf[0] = '%'; while (c = *p++) switch (c) { case '%': c = *p++; q = &buf[1]; while ((c >= '0' && c <= '9') || c == '.') { *q++ = c; c = *p++; } switch (c) { case '%': fprintf (file, "%%"); break; case 'd': case 'i': case 'u': case 'x': case 'p': case 'X': case 'o': *q++ = c; *q = 0; fprintf (file, buf, va_arg (argptr, int)); break; case 'e': case 'f': case 'g': *q++ = c; *q = 0; fprintf (file, buf, va_arg (argptr, double)); break; case 's': *q++ = c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -