m68hc11.c
来自「gcc3.2.1源代码」· C语言 代码 · 共 2,530 行 · 第 1/5 页
C
2,530 行
return x; } abort ();}/* Obscure register manipulation. *//* Finds backward in the instructions to see if register 'reg' is dead. This is used when generating code to see if we can use 'reg' as a scratch register. This allows us to choose a better generation of code when we know that some register dies or can be clobbered. */intdead_register_here (x, reg) rtx x; rtx reg;{ rtx x_reg; rtx p; if (D_REG_P (reg)) x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM); else x_reg = 0; for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p)) if (GET_RTX_CLASS (GET_CODE (p)) == 'i') { rtx body; body = PATTERN (p); if (GET_CODE (body) == CALL_INSN) break; if (GET_CODE (body) == JUMP_INSN) break; if (GET_CODE (body) == SET) { rtx dst = XEXP (body, 0); if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg)) break; if (x_reg && rtx_equal_p (dst, x_reg)) break; if (find_regno_note (p, REG_DEAD, REGNO (reg))) return 1; } else if (reg_mentioned_p (reg, p) || (x_reg && reg_mentioned_p (x_reg, p))) break; } /* Scan forward to see if the register is set in some insns and never used since then. */ for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p)) { rtx body; if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER) break; if (GET_CODE (p) != INSN) continue; body = PATTERN (p); if (GET_CODE (body) == SET) { rtx src = XEXP (body, 1); rtx dst = XEXP (body, 0); if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src)) return 1; } /* Register is used (may be in source or in dest). */ if (reg_mentioned_p (reg, p) || (x_reg != 0 && GET_MODE (p) == SImode && reg_mentioned_p (x_reg, p))) break; } return p == 0 ? 1 : 0;}/* Code generation operations called from machine description file. *//* Print the name of register 'regno' in the assembly file. */static voidasm_print_register (file, regno) FILE *file; int regno;{ const char *name = reg_names[regno]; if (TARGET_NO_DIRECT_MODE && name[0] == '*') name++; asm_fprintf (file, "%s", name);}/* A C compound statement to output to stdio stream STREAM the assembler syntax for an instruction operand X. X is an RTL expression. CODE is a value that can be used to specify one of several ways of printing the operand. It is used when identical operands must be printed differently depending on the context. CODE comes from the `%' specification that was used to request printing of the operand. If the specification was just `%DIGIT' then CODE is 0; if the specification was `%LTR DIGIT' then CODE is the ASCII code for LTR. If X is a register, this macro should print the register's name. The names can be found in an array `reg_names' whose type is `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. When the machine description has a specification `%PUNCT' (a `%' followed by a punctuation character), this macro is called with a null pointer for X and the punctuation character for CODE. The M68HC11 specific codes are: 'b' for the low part of the operand. 'h' for the high part of the operand The 'b' or 'h' modifiers have no effect if the operand has the QImode and is not a S_REG_P (soft register). If the operand is a hard register, these two modifiers have no effect. 't' generate the temporary scratch register. The operand is ignored. 'T' generate the low-part temporary scratch register. The operand is ignored. */voidprint_operand (file, op, letter) FILE *file; rtx op; int letter;{ if (letter == 't') { asm_print_register (file, SOFT_TMP_REGNUM); return; } else if (letter == 'T') { asm_print_register (file, SOFT_TMP_REGNUM); asm_fprintf (file, "+1"); return; } else if (letter == '#') { asm_fprintf (file, "%0I"); } if (GET_CODE (op) == REG) { if (letter == 'b' && S_REG_P (op)) { asm_print_register (file, REGNO (op)); asm_fprintf (file, "+1"); } else { asm_print_register (file, REGNO (op)); } return; } if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h')) { if (letter == 'b') asm_fprintf (file, "%0I%%lo("); else asm_fprintf (file, "%0I%%hi("); output_addr_const (file, op); asm_fprintf (file, ")"); return; } /* Get the low or high part of the operand when 'b' or 'h' modifiers are specified. If we already have a QImode, there is nothing to do. */ if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode) { if (letter == 'b') { op = m68hc11_gen_lowpart (QImode, op); } else if (letter == 'h') { op = m68hc11_gen_highpart (QImode, op); } } if (GET_CODE (op) == MEM) { rtx base = XEXP (op, 0); switch (GET_CODE (base)) { case PRE_DEC: if (TARGET_M6812) { asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op))); asm_print_register (file, REGNO (XEXP (base, 0))); } else abort (); break; case POST_DEC: if (TARGET_M6812) { asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); asm_print_register (file, REGNO (XEXP (base, 0))); asm_fprintf (file, "-"); } else abort (); break; case POST_INC: if (TARGET_M6812) { asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); asm_print_register (file, REGNO (XEXP (base, 0))); asm_fprintf (file, "+"); } else abort (); break; case PRE_INC: if (TARGET_M6812) { asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op))); asm_print_register (file, REGNO (XEXP (base, 0))); } else abort (); break; default: output_address (base); break; } } else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode) { REAL_VALUE_TYPE r; long l; REAL_VALUE_FROM_CONST_DOUBLE (r, op); REAL_VALUE_TO_TARGET_SINGLE (r, l); asm_fprintf (file, "%I0x%lx", l); } else if (GET_CODE (op) == CONST_DOUBLE && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode)) { REAL_VALUE_TYPE r; char dstr[30]; REAL_VALUE_FROM_CONST_DOUBLE (r, op); REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr); asm_fprintf (file, "%I0r%s", dstr); } else { int need_parenthesize = 0; if (letter != 'i') asm_fprintf (file, "%0I"); else need_parenthesize = must_parenthesize (op); if (need_parenthesize) asm_fprintf (file, "("); output_addr_const (file, op); if (need_parenthesize) asm_fprintf (file, ")"); }}/* Returns true if the operand 'op' must be printed with parenthesis arround it. This must be done only if there is a symbol whose name is a processor register. */static intmust_parenthesize (op) rtx op;{ const char *name; switch (GET_CODE (op)) { case SYMBOL_REF: name = XSTR (op, 0); /* Avoid a conflict between symbol name and a possible register. */ return (strcasecmp (name, "a") == 0 || strcasecmp (name, "b") == 0 || strcasecmp (name, "d") == 0 || strcasecmp (name, "x") == 0 || strcasecmp (name, "y") == 0 || strcasecmp (name, "ix") == 0 || strcasecmp (name, "iy") == 0 || strcasecmp (name, "pc") == 0 || strcasecmp (name, "sp") == 0 || strcasecmp (name, "ccr") == 0) ? 1 : 0; case PLUS: case MINUS: return must_parenthesize (XEXP (op, 0)) || must_parenthesize (XEXP (op, 1)); case MEM: case CONST: case ZERO_EXTEND: case SIGN_EXTEND: return must_parenthesize (XEXP (op, 0)); case CONST_DOUBLE: case CONST_INT: case LABEL_REF: case CODE_LABEL: default: return 0; }}/* A C compound statement to output to stdio stream STREAM the assembler syntax for an instruction operand that is a memory reference whose address is ADDR. ADDR is an RTL expression. */voidprint_operand_address (file, addr) FILE *file; rtx addr;{ rtx base; rtx offset; int need_parenthesis = 0; switch (GET_CODE (addr)) { case REG: if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr)) abort (); asm_fprintf (file, "0,"); asm_print_register (file, REGNO (addr)); break; case MEM: base = XEXP (addr, 0); switch (GET_CODE (base)) { case PRE_DEC: if (TARGET_M6812) { asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr))); asm_print_register (file, REGNO (XEXP (base, 0))); } else abort (); break; case POST_DEC: if (TARGET_M6812) { asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); asm_print_register (file, REGNO (XEXP (base, 0))); asm_fprintf (file, "-"); } else abort (); break; case POST_INC: if (TARGET_M6812) { asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); asm_print_register (file, REGNO (XEXP (base, 0))); asm_fprintf (file, "+"); } else abort (); break; case PRE_INC: if (TARGET_M6812) { asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr))); asm_print_register (file, REGNO (XEXP (base, 0))); } else abort (); break; default: need_parenthesis = must_parenthesize (base); if (need_parenthesis) asm_fprintf (file, "("); output_addr_const (file, base); if (need_parenthesis) asm_fprintf (file, ")"); break; } break; case PLUS: base = XEXP (addr, 0); offset = XEXP (addr, 1); if (!G_REG_P (base) && G_REG_P (offset)) { base = XEXP (addr, 1); offset = XEXP (addr, 0); } if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset))) { need_parenthesis = must_parenthesize (addr); if (need_parenthesis) asm_fprintf (file, "("); output_addr_const (file, base); asm_fprintf (file, "+"); output_addr_const (file, offset); if (need_parenthesis) asm_fprintf (file, ")"); } else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base)) { if (REG_P (offset)) { if (TARGET_M6812) { asm_print_register (file, REGNO (offset)); asm_fprintf (file, ","); asm_print_register (file, REGNO (base)); } else abort (); } else { need_parenthesis = must_parenthesize (offset); if (need_parenthesis) asm_fprintf (file, "("); output_addr_const (file, offset); if (need_parenthesis) asm_fprintf (file, ")"); asm_fprintf (file, ","); asm_print_register (file, REGNO (base)); } } else { abort (); } break; default: if (GET_CODE (addr) == CONST_INT && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000) { asm_fprintf (file, "%d", INTVAL (addr)); } else { need_parenthesis = must_parenthesize (addr); if (need_parenthesis) asm_fprintf (file, "("); output_addr_const (file, addr); if (need_parenthesis) asm_fprintf (file, ")"); } break; }}/* Splitting of some instructions. */static rtxm68hc11_expand_compare (code, op0, op1) enum rtx_code code; rtx op0, op1;{ rtx ret = 0; if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) abort (); else { emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, gen_rtx_COMPARE (VOIDmode, op0, op1)));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?