📄 mips.c
字号:
{ const char *ret = 0; rtx op0 = operands[0]; rtx op1 = operands[1]; enum rtx_code code0 = GET_CODE (operands[0]); enum rtx_code code1 = GET_CODE (operands[1]); int subreg_word0 = 0; int subreg_word1 = 0; enum delay_type delay = DELAY_NONE; while (code0 == SUBREG) { subreg_word0 += SUBREG_WORD (op0); op0 = SUBREG_REG (op0); code0 = GET_CODE (op0); } if (code1 == SIGN_EXTEND) { op1 = XEXP (op1, 0); code1 = GET_CODE (op1); } while (code1 == SUBREG) { subreg_word1 += SUBREG_WORD (op1); op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); } /* Sanity check. */ if (GET_CODE (operands[1]) == SIGN_EXTEND && code1 != REG && 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) && !TARGET_MIPS16) { 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) { if (! TARGET_MIPS16) 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 && ! TARGET_MIPS16) { 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; ret = (regno0 == HILO_REGNUM ? "mtlo\t%.\n\tmthi\t%." : "mt%0\t%.\n"); } } else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) { if (TARGET_64BIT) { if (TARGET_MIPS16) { if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff) ret = "li\t%0,%1"; else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff) ret = "li\t%0,%n1\n\tneg\t%0"; } else 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); if (TARGET_MIPS16) { if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff) ret = "li\t%M0,%2\n\tli\t%L0,%1"; else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff) { operands[2] = GEN_INT (1); ret = "li\t%M0,%2\n\tneg\t%M0\n\tli\t%L0,%n1\n\tneg\t%L0"; } } else 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)) ret = (double_memory_operand (op1, GET_MODE (op1)) ? "lwu\t%0,%1\n\tlwu\t%D0,4+%1" : "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 (double_memory_operand (op1, GET_MODE (op1))) { operands[2] = adj_offsettable_operand (op1, 4); ret = (reg_mentioned_p (op0, op1) ? "lw\t%D0,%2\n\tlw\t%0,%1" : "lw\t%0,%1\n\tlw\t%D0,%2"); } if (ret != 0 && MEM_VOLATILE_P (op1)) { size_t i = strlen (ret); if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) abort (); sprintf (volatile_buffer, "%%{%s%%}", ret); ret = volatile_buffer; } } else if (code1 == LABEL_REF) { 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 (code1 == SYMBOL_REF || code1 == CONST) { if (TARGET_MIPS16 && code1 == CONST && GET_CODE (XEXP (op1, 0)) == REG && REGNO (XEXP (op1, 0)) == GP_REG_FIRST + 28) { /* This case arises on the mips16; see mips16_gp_pseudo_reg. */ ret = "move\t%0,%+"; } else if (TARGET_MIPS16 && code1 == SYMBOL_REF && SYMBOL_REF_FLAG (op1) && (XSTR (op1, 0)[0] != '*' || strncmp (XSTR (op1, 0) + 1, LOCAL_LABEL_PREFIX, sizeof LOCAL_LABEL_PREFIX - 1) != 0)) { /* This can occur when reloading the address of a GP relative symbol on the mips16. */ ret = "move\t%0,%+\n\taddu\t%0,%%gprel(%a1)"; } else { 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 (double_memory_operand (op0, GET_MODE (op0))) { 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 || double_memory_operand (op0, GET_MODE (op0)))) { 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 != 0 && MEM_VOLATILE_P (op0)) { size_t i = strlen (ret); if (i > sizeof (volatile_buffer) - sizeof ("%{%}")) abort (); sprintf (volatile_buffer, "%%{%s%%}", ret); ret = volatile_buffer; } } if (ret == 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)) { 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)) { 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; default: break; } } default: break; } return 4;}/* Return nonzero if X is an address which needs a temporary register when reloaded while generating PIC code. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -