📄 mips.c
字号:
ret = "mov.s\t%0,%1"; } else if (MD_REG_P (regno0)) { if (GP_REG_P (regno1)) { delay = DELAY_HILO; if (regno0 != HILO_REGNUM && ! TARGET_MIPS16) ret = "mt%0\t%1"; } } else if (regno0 == FPSW_REGNUM && ! ISA_HAS_8CC) { if (GP_REG_P (regno1)) { delay = DELAY_LOAD; ret = "ctc1\t%0,$31"; } } } else if (code1 == MEM) { delay = DELAY_LOAD; if (TARGET_STATS) mips_count_memory_refs (op1, 1); if (GP_REG_P (regno0)) { /* For loads, use the mode of the memory item, instead of the target, so zero/sign extend can use this code as well. */ switch (GET_MODE (op1)) { default: break; case SFmode: ret = "lw\t%0,%1"; break; case SImode: case CCmode: ret = ((unsignedp && TARGET_64BIT) ? "lwu\t%0,%1" : "lw\t%0,%1"); break; case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break; case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break; } } else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode)) ret = "l.s\t%0,%1"; if (ret != (char *)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 == CONST_INT || (code1 == CONST_DOUBLE && GET_MODE (op1) == VOIDmode)) { if (code1 == CONST_DOUBLE) { /* This can happen when storing constants into long long bitfields. Just store the least significant word of the value. */ operands[1] = op1 = GEN_INT (CONST_DOUBLE_LOW (op1)); } if (INTVAL (op1) == 0 && ! TARGET_MIPS16) { if (GP_REG_P (regno0)) ret = "move\t%0,%z1"; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; ret = "mtc1\t%z1,%0"; } else if (MD_REG_P (regno0)) { delay = DELAY_HILO; ret = "mt%0\t%."; } } else if (GP_REG_P (regno0)) { /* Don't use X format, because that will give out of range numbers for 64 bit host and 32 bit target. */ if (! TARGET_MIPS16) ret = "li\t%0,%1\t\t\t# %X1"; else { 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 (code1 == CONST_DOUBLE && mode == SFmode) { if (op1 == CONST0_RTX (SFmode)) { if (GP_REG_P (regno0)) ret = "move\t%0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; ret = "mtc1\t%.,%0"; } } else { delay = DELAY_LOAD; ret = "li.s\t%0,%1"; } } else if (code1 == LABEL_REF) { if (TARGET_STATS) mips_count_memory_refs (op1, 1); ret = "la\t%0,%a1"; } else if (code1 == SYMBOL_REF || code1 == CONST) { if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1)) { rtx offset = const0_rtx; if (GET_CODE (op1) == CONST) op1 = eliminate_constant_term (XEXP (op1, 0), &offset); if (GET_CODE (op1) == SYMBOL_REF) { operands[2] = HALF_PIC_PTR (op1); if (TARGET_STATS) mips_count_memory_refs (operands[2], 1); if (INTVAL (offset) == 0) { delay = DELAY_LOAD; ret = (unsignedp && TARGET_64BIT ? "lwu\t%0,%2" : "lw\t%0,%2"); } else { dslots_load_total++; operands[3] = offset; if (unsignedp && TARGET_64BIT) ret = (SMALL_INT (offset) ? "lwu\t%0,%2%#\n\tadd\t%0,%0,%3" : "lwu\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"); else ret = (SMALL_INT (offset) ? "lw\t%0,%2%#\n\tadd\t%0,%0,%3" : "lw\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]"); } } } else 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, 1); ret = "la\t%0,%a1"; } } else if (code1 == PLUS) { rtx add_op0 = XEXP (op1, 0); rtx add_op1 = XEXP (op1, 1); if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT) add_op0 = XEXP (op1, 1), add_op1 = XEXP (op1, 0); operands[2] = add_op0; operands[3] = add_op1; ret = "add%:\t%0,%2,%3"; } else if (code1 == HIGH) { operands[1] = XEXP (op1, 0); ret = "lui\t%0,%%hi(%1)"; } } else if (code0 == MEM) { if (TARGET_STATS) mips_count_memory_refs (op0, 1); if (code1 == REG) { int regno1 = REGNO (op1) + subreg_offset1; if (GP_REG_P (regno1)) { switch (mode) { case SFmode: ret = "sw\t%1,%0"; break; case SImode: ret = "sw\t%1,%0"; break; case HImode: ret = "sh\t%1,%0"; break; case QImode: ret = "sb\t%1,%0"; break; default: break; } } else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode)) ret = "s.s\t%1,%0"; } else if (code1 == CONST_INT && INTVAL (op1) == 0) { switch (mode) { case SFmode: ret = "sw\t%z1,%0"; break; case SImode: ret = "sw\t%z1,%0"; break; case HImode: ret = "sh\t%z1,%0"; break; case QImode: ret = "sb\t%z1,%0"; break; default: break; } } else if (code1 == CONST_DOUBLE && op1 == CONST0_RTX (mode)) { switch (mode) { case SFmode: ret = "sw\t%.,%0"; break; case SImode: ret = "sw\t%.,%0"; break; case HImode: ret = "sh\t%.,%0"; break; case QImode: ret = "sb\t%.,%0"; break; default: break; } } 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;}/* Return the appropriate instructions to move 2 words */const char *mips_move_2words (operands, insn) rtx operands[]; rtx insn;{ 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_offset0 = 0; int subreg_offset1 = 0; enum delay_type delay = DELAY_NONE; while (code0 == SUBREG) { subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)), GET_MODE (SUBREG_REG (op0)), SUBREG_BYTE (op0), GET_MODE (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_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)), GET_MODE (SUBREG_REG (op1)), SUBREG_BYTE (op1), GET_MODE (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_offset0; if (code1 == REG) { int regno1 = REGNO (op1) + subreg_offset1; /* 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 /* GNU as emits 64-bit code for li.d if the ISA is 3 or higher. For !TARGET_64BIT && gp registers we need to avoid this by using two li instructions instead. */ if (ISA_HAS_64BIT_REGS && ! TARGET_64BIT && ! FP_REG_P (regno0)) { spl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -