📄 mips.c
字号:
&& code1 != CONST_INT /* The following three can happen as the result of a questionable cast. */ && code1 != LABEL_REF && code1 != SYMBOL_REF && code1 != CONST) abort (); if (code0 == REG) { int regno0 = REGNO (op0) + subreg_word0; if (code1 == REG) { int regno1 = REGNO (op1) + subreg_word1; /* Just in case, don't do anything for assigning a register to itself, unless we are filling a delay slot. */ if (regno0 == regno1 && set_nomacro == 0) ret = ""; else if (FP_REG_P (regno0)) { if (FP_REG_P (regno1)) ret = "mov.d\t%0,%1"; else { delay = DELAY_LOAD; if (TARGET_FLOAT64) { if (!TARGET_64BIT) abort_with_insn (insn, "Bad move");#ifdef TARGET_FP_CALL_32 if (FP_CALL_GP_REG_P (regno1)) ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tdmtc1\t%1,%0"; else#endif ret = "dmtc1\t%1,%0"; } else ret = "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; } } else if (FP_REG_P (regno1)) { delay = DELAY_LOAD; if (TARGET_FLOAT64) { if (!TARGET_64BIT) abort_with_insn (insn, "Bad move");#ifdef TARGET_FP_CALL_32 if (FP_CALL_GP_REG_P (regno0)) ret = "dmfc1\t%0,%1\n\tmfc1\t%D0,%1\n\tdsrl\t%0,32"; else#endif ret = "dmfc1\t%0,%1"; } else ret = "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; } else if (MD_REG_P (regno0) && GP_REG_P (regno1)) { delay = DELAY_HILO; if (TARGET_64BIT) { if (regno0 != HILO_REGNUM) ret = "mt%0\t%1"; else if (regno1 == 0) ret = "mtlo\t%.\n\tmthi\t%."; } else ret = "mthi\t%M1\n\tmtlo\t%L1"; } else if (GP_REG_P (regno0) && MD_REG_P (regno1)) { delay = DELAY_HILO; if (TARGET_64BIT) { if (regno1 != HILO_REGNUM) ret = "mf%1\t%0"; } else ret = "mfhi\t%M0\n\tmflo\t%L0"; } else if (TARGET_64BIT) ret = "move\t%0,%1"; else if (regno0 != (regno1+1)) ret = "move\t%0,%1\n\tmove\t%D0,%D1"; else ret = "move\t%D0,%D1\n\tmove\t%0,%1"; } else if (code1 == CONST_DOUBLE) { /* Move zero from $0 unless !TARGET_64BIT and recipient is 64-bit fp reg, in which case generate a constant. */ if (op1 != CONST0_RTX (GET_MODE (op1)) || (TARGET_FLOAT64 && !TARGET_64BIT && FP_REG_P (regno0))) { if (GET_MODE (op1) == DFmode) { delay = DELAY_LOAD;#ifdef TARGET_FP_CALL_32 if (FP_CALL_GP_REG_P (regno0)) { if (TARGET_FLOAT64 && !TARGET_64BIT) { split_double (op1, operands + 2, operands + 3); ret = "li\t%0,%2\n\tli\t%D0,%3"; } else ret = "li.d\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32"; } else#endif ret = "li.d\t%0,%1"; } else if (TARGET_64BIT) ret = "dli\t%0,%1"; else { split_double (op1, operands + 2, operands + 3); ret = "li\t%0,%2\n\tli\t%D0,%3"; } } else { if (GP_REG_P (regno0)) ret = (TARGET_64BIT#ifdef TARGET_FP_CALL_32 && ! FP_CALL_GP_REG_P (regno0)#endif ) ? "move\t%0,%." : "move\t%0,%.\n\tmove\t%D0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; ret = (TARGET_64BIT) ? "dmtc1\t%.,%0" : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; } } } else if (code1 == CONST_INT && INTVAL (op1) == 0) { if (GP_REG_P (regno0)) ret = (TARGET_64BIT) ? "move\t%0,%." : "move\t%0,%.\n\tmove\t%D0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; ret = (TARGET_64BIT) ? "dmtc1\t%.,%0" : (TARGET_FLOAT64 ? "li.d\t%0,%1" : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"); } else if (MD_REG_P (regno0)) { delay = DELAY_HILO; if (regno0 != HILO_REGNUM) ret = "mt%0\t%.\n"; else ret = "mtlo\t%.\n\tmthi\t%."; } } else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) { if (TARGET_64BIT) { if (GET_CODE (operands[1]) == SIGN_EXTEND) ret = "li\t%0,%1\t\t# %X1"; else if (HOST_BITS_PER_WIDE_INT < 64) /* We can't use 'X' for negative numbers, because then we won't get the right value for the upper 32 bits. */ ret = ((INTVAL (op1) < 0) ? "dli\t%0,%1\t\t\t# %X1" : "dli\t%0,%X1\t\t# %1"); else /* We must use 'X', because otherwise LONG_MIN will print as a number that the assembler won't accept. */ ret = "dli\t%0,%X1\t\t# %1"; } else if (HOST_BITS_PER_WIDE_INT < 64) { operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1); ret = "li\t%M0,%2\n\tli\t%L0,%1"; } else { /* We use multiple shifts here, to avoid warnings about out of range shifts on 32 bit hosts. */ operands[2] = GEN_INT (INTVAL (operands[1]) >> 16 >> 16); operands[1] = GEN_INT (INTVAL (operands[1]) << 16 << 16 >> 16 >> 16); ret = "li\t%M0,%2\n\tli\t%L0,%1"; } } else if (code1 == MEM) { delay = DELAY_LOAD; if (TARGET_STATS) mips_count_memory_refs (op1, 2); if (FP_REG_P (regno0)) ret = "l.d\t%0,%1"; else if (TARGET_64BIT) {#ifdef TARGET_FP_CALL_32 if (FP_CALL_GP_REG_P (regno0)) { if (offsettable_address_p (FALSE, SImode, op1)) ret = "lwu\t%0,%1\n\tlwu\t%D0,4+%1"; else ret = "ld\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32"; } else#endif ret = "ld\t%0,%1"; } else if (offsettable_address_p (1, DFmode, XEXP (op1, 0))) { operands[2] = adj_offsettable_operand (op1, 4); if (reg_mentioned_p (op0, op1)) ret = "lw\t%D0,%2\n\tlw\t%0,%1"; else ret = "lw\t%0,%1\n\tlw\t%D0,%2"; } if (ret != (char *)0 && MEM_VOLATILE_P (op1)) { int i = strlen (ret); if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) abort (); sprintf (volatile_buffer, "%%{%s%%}", ret); ret = volatile_buffer; } } else if (code1 == LABEL_REF || code1 == SYMBOL_REF || code1 == CONST) { if (TARGET_STATS) mips_count_memory_refs (op1, 2); if (GET_CODE (operands[1]) == SIGN_EXTEND) /* We deliberately remove the 'a' from '%1', so that we don't have to add SIGN_EXTEND support to print_operand_address. print_operand will just call print_operand_address in this case, so there is no problem. */ ret = "la\t%0,%1"; else ret = "dla\t%0,%a1"; } } else if (code0 == MEM) { if (code1 == REG) { int regno1 = REGNO (op1) + subreg_word1; if (FP_REG_P (regno1)) ret = "s.d\t%1,%0"; else if (TARGET_64BIT) {#ifdef TARGET_FP_CALL_32 if (FP_CALL_GP_REG_P (regno1)) ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tsd\t%1,%0"; else#endif ret = "sd\t%1,%0"; } else if (offsettable_address_p (1, DFmode, XEXP (op0, 0))) { operands[2] = adj_offsettable_operand (op0, 4); ret = "sw\t%1,%0\n\tsw\t%D1,%2"; } } else if (((code1 == CONST_INT && INTVAL (op1) == 0) || (code1 == CONST_DOUBLE && op1 == CONST0_RTX (GET_MODE (op1)))) && (TARGET_64BIT || offsettable_address_p (1, DFmode, XEXP (op0, 0)))) { if (TARGET_64BIT) ret = "sd\t%.,%0"; else { operands[2] = adj_offsettable_operand (op0, 4); ret = "sw\t%.,%0\n\tsw\t%.,%2"; } } if (TARGET_STATS) mips_count_memory_refs (op0, 2); if (ret != (char *)0 && MEM_VOLATILE_P (op0)) { int i = strlen (ret); if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) abort (); sprintf (volatile_buffer, "%%{%s%%}", ret); ret = volatile_buffer; } } if (ret == (char *)0) { abort_with_insn (insn, "Bad move"); return 0; } if (delay != DELAY_NONE) return mips_fill_delay_slot (ret, delay, operands, insn); return ret;}/* Provide the costs of an addressing mode that contains ADDR. If ADDR is not a valid address, its cost is irrelevant. */intmips_address_cost (addr) rtx addr;{ switch (GET_CODE (addr)) { default: break; case LO_SUM: return 1; case LABEL_REF: return 2; case CONST: { rtx offset = const0_rtx; addr = eliminate_constant_term (XEXP (addr, 0), &offset); if (GET_CODE (addr) == LABEL_REF) return 2; if (GET_CODE (addr) != SYMBOL_REF) return 4; if (! SMALL_INT (offset)) return 2; } /* fall through */ case SYMBOL_REF: return SYMBOL_REF_FLAG (addr) ? 1 : 2; case PLUS: { register rtx plus0 = XEXP (addr, 0); register rtx plus1 = XEXP (addr, 1); if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG) { plus0 = XEXP (addr, 1); plus1 = XEXP (addr, 0); } if (GET_CODE (plus0) != REG) break; switch (GET_CODE (plus1)) { default: break; case CONST_INT: return (SMALL_INT (plus1) ? 1 : 2); case CONST: case SYMBOL_REF: case LABEL_REF: case HIGH: case LO_SUM: return mips_address_cost (plus1) + 1; } } } return 4;}/* Return true if X is an address which needs a temporary register when reloaded while generating PIC code. */intpic_address_needs_scratch (x) rtx x;{ /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) return 1; return 0;}/* Make normal rtx_code into something we can index from an array */static enum internal_testmap_test_to_internal_test (test_code) enum rtx_code test_code;{ enum internal_test test = ITEST_MAX; switch (test_code) { default: break; case EQ: test = ITEST_EQ; break; case NE: test = ITEST_NE; break; case GT: test = ITEST_GT; break; case GE: test = ITEST_GE; break; case LT: test = ITEST_LT; break; case LE: test = ITEST_LE; break; case GTU: test = ITEST_GTU; break; case GEU: test = ITEST_GEU; break; case LTU: test = ITEST_LTU; break; case LEU: test = ITEST_LEU; break; } return test;}/* Generate the code to compare two integer values. The return value is: (reg:SI xx) The pseudo register the comparison is in (rtx)0 No register, generate a simple branch. ??? This is called with result nonzero by the Scond patterns in mips.md. These patterns are called with a target in the mode of the Scond instruction pattern. Since this must be a constant, we must use SImode. This means that if RESULT is non-zero, it will always be an SImode register, even if TARGET_64BIT is true. We cope with this by calling convert_move rather than emit_move_insn. This will sometimes lead to an unnecessary extension of the result; for example: long long foo (long long i) { return i < 5; } */rtxgen_int_relational (test_code, result, cmp0, cmp1, p_invert) enum rtx_code test_code; /* relational test (EQ, etc) */ rtx result; /* result to store comp. or 0 if branch */ rtx cmp0; /* first operand to compare */ rtx cmp1; /* second operand to compare */ int *p_invert; /* NULL or ptr to hold whether branch needs */ /* to reverse its test */{ struct cmp_info { enum rtx_code test_code; /* code to use in instruction (LT vs. LTU) */ int const_low; /* low bound of constant we can accept */ int const_high; /* high bound of constant we can accept */ int const_add; /* constant to add (convert LE -> LT) */ int reverse_regs; /* reverse registers in test */ int invert_const; /* != 0 if invert value if cmp1 is constant */ int invert_reg; /* != 0 if invert value if cmp1 is register */ int unsignedp; /* != 0 for unsigned comparisons. */ }; static struct cmp_info info[ (int)ITEST_MAX ] = { { XOR, 0, 65535, 0, 0, 0, 0, 0 }, /* EQ */ { XOR, 0, 65535, 0, 0, 1, 1, 0 }, /* NE */ { LT, -32769, 32766, 1, 1, 1, 0, 0 }, /* GT */ { LT, -32768, 32767, 0, 0, 1, 1, 0 }, /* GE */ { LT, -32768, 32767, 0, 0, 0, 0, 0 }, /* LT */ { LT, -32769, 32766, 1, 1, 0, 1, 0 }, /* LE */ { LTU, -32769, 32766, 1, 1, 1, 0, 1 }, /* GTU */ { LTU, -32768, 32767, 0, 0, 1, 1, 1 }, /* GEU */ { LTU, -32768, 32767, 0, 0, 0, 0, 1 }, /* LTU */ { LTU, -32769, 32766, 1, 1, 0, 1, 1 }, /* LEU */ }; enum internal_test test; enum machine_mode mode; struct cmp_info *p_info; int branch_p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -