📄 mips.c
字号:
ret = (INTVAL (op1) < 0) ? "li\t%0,%1\t\t\t# %X1" : "li\t%0,%X1\t\t# %1"; } else if (code1 == CONST_DOUBLE && mode == SFmode) { if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) { 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 = "lw\t%0,%2"; } else { dslots_load_total++; operands[3] = offset; 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_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); /* reverse operands */ add_op1 = XEXP (op1, 0); } operands[2] = add_op0; operands[3] = add_op1; ret = "add%:\t%0,%2,%3"; } } else if (code0 == MEM) { if (TARGET_STATS) mips_count_memory_refs (op0, 1); if (code1 == REG) { int regno1 = REGNO (op1) + subreg_word1; if (GP_REG_P (regno1)) { switch (mode) { default: break; 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; } } 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) { default: break; 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; } } else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0) { switch (mode) { default: break; 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; } } 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;}/* Return the appropriate instructions to move 2 words */char *mips_move_2words (operands, insn) rtx operands[]; rtx insn;{ 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); } while (code1 == SUBREG) { subreg_word1 += SUBREG_WORD (op1); op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); } 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; ret = (TARGET_FLOAT64) ? "dmtc1\t%1,%0" : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0"; } } else if (FP_REG_P (regno1)) { delay = DELAY_LOAD; ret = (TARGET_FLOAT64) ? "dmfc1\t%0,%1" : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1"; } else if (MD_REG_P (regno0) && GP_REG_P (regno1)) { delay = DELAY_HILO; ret = "mthi\t%M1\n\tmtlo\t%L1"; } else if (GP_REG_P (regno0) && MD_REG_P (regno1)) { delay = DELAY_HILO; ret = "mfhi\t%M0\n\tmflo\t%L0"; } 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) { if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0) { if (GET_MODE (op1) == DFmode) { delay = DELAY_LOAD; ret = "li.d\t%0,%1"; } else { operands[2] = GEN_INT (CONST_DOUBLE_LOW (op1)); operands[3] = GEN_INT (CONST_DOUBLE_HIGH (op1)); ret = "li\t%M0,%3\n\tli\t%L0,%2"; } } else { if (GP_REG_P (regno0)) ret = "move\t%0,%.\n\tmove\t%D0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; ret = (TARGET_FLOAT64) ? "dmtc1\t%.,%0" : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; } } } else if (code1 == CONST_INT && INTVAL (op1) == 0) { if (GP_REG_P (regno0)) ret = "move\t%0,%.\n\tmove\t%D0,%."; else if (FP_REG_P (regno0)) { delay = DELAY_LOAD; ret = (TARGET_FLOAT64) ? "dmtc1\t%.,%0" : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"; } } else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0)) { operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1); 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 (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 (code0 == MEM) { if (code1 == REG) { int regno1 = REGNO (op1) + subreg_word1; if (FP_REG_P (regno1)) ret = "s.d\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_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0 && offsettable_address_p (1, DFmode, XEXP (op0, 0))) { if (TARGET_FLOAT64) 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: case HIGH: return 1; case LABEL_REF: return 2; case CONST: { rtx offset = const0_rtx; addr = eliminate_constant_term (addr, &offset); if (GET_CODE (addr) == LABEL_REF) return 2; if (GET_CODE (addr) != SYMBOL_REF) return 4; if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767) 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: { int value = INTVAL (plus1); return (value < -32768 || value > 32767) ? 2 : 1; } case CONST: case SYMBOL_REF: case LABEL_REF: case HIGH: case LO_SUM: return mips_address_cost (plus1) + 1; } } } return 4;}/* 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. */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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -