📄 mips.c
字号:
if (type == DELAY_LOAD || type == DELAY_FCMP) num_nops = 1; else if (type == DELAY_HILO) num_nops = 2; else num_nops = 0; /* Make sure that we don't put nop's after labels. */ next_insn = NEXT_INSN (cur_insn); while (next_insn != 0 && GET_CODE (next_insn) == NOTE) next_insn = NEXT_INSN (next_insn); dslots_load_total += num_nops; if (TARGET_DEBUG_F_MODE || !optimize || type == DELAY_NONE || operands == 0 || cur_insn == 0 || next_insn == 0 || GET_CODE (next_insn) == CODE_LABEL || (set_reg = operands[0]) == 0) { dslots_number_nops = 0; mips_load_reg = 0; mips_load_reg2 = 0; mips_load_reg3 = 0; mips_load_reg4 = 0; return ret; } set_reg = operands[0]; if (set_reg == 0) return ret; while (GET_CODE (set_reg) == SUBREG) set_reg = SUBREG_REG (set_reg); mode = GET_MODE (set_reg); dslots_number_nops = num_nops; mips_load_reg = set_reg; if (GET_MODE_SIZE (mode) > (unsigned) (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD)) mips_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1); else mips_load_reg2 = 0; if (type == DELAY_HILO) { mips_load_reg3 = gen_rtx_REG (SImode, MD_REG_FIRST); mips_load_reg4 = gen_rtx_REG (SImode, MD_REG_FIRST+1); } else { mips_load_reg3 = 0; mips_load_reg4 = 0; } return ret;}/* Determine whether a memory reference takes one (based off of the GP pointer), two (normal), or three (label + reg) instructions, and bump the appropriate counter for -mstats. */voidmips_count_memory_refs (op, num) rtx op; int num;{ int additional = 0; int n_words = 0; rtx addr, plus0, plus1; enum rtx_code code0, code1; int looping; if (TARGET_DEBUG_B_MODE) { fprintf (stderr, "\n========== mips_count_memory_refs:\n"); debug_rtx (op); } /* Skip MEM if passed, otherwise handle movsi of address. */ addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0); /* Loop, going through the address RTL. */ do { looping = FALSE; switch (GET_CODE (addr)) { case REG: case CONST_INT: case LO_SUM: break; case PLUS: plus0 = XEXP (addr, 0); plus1 = XEXP (addr, 1); code0 = GET_CODE (plus0); code1 = GET_CODE (plus1); if (code0 == REG) { additional++; addr = plus1; looping = 1; continue; } if (code0 == CONST_INT) { addr = plus1; looping = 1; continue; } if (code1 == REG) { additional++; addr = plus0; looping = 1; continue; } if (code1 == CONST_INT) { addr = plus0; looping = 1; continue; } if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST) { addr = plus0; looping = 1; continue; } if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST) { addr = plus1; looping = 1; continue; } break; case LABEL_REF: n_words = 2; /* always 2 words */ break; case CONST: addr = XEXP (addr, 0); looping = 1; continue; case SYMBOL_REF: n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2; break; default: break; } } while (looping); if (n_words == 0) return; n_words += additional; if (n_words > 3) n_words = 3; num_refs[n_words-1] += num;}/* Return a pseudo that points to the address of the current function. The first time it is called for a function, an initializer for the pseudo is emitted in the beginning of the function. */rtxembedded_pic_fnaddr_reg (){ if (cfun->machine->embedded_pic_fnaddr_rtx == NULL) { rtx seq; cfun->machine->embedded_pic_fnaddr_rtx = gen_reg_rtx (Pmode); /* Output code at function start to initialize the pseudo-reg. */ /* ??? We used to do this in FINALIZE_PIC, but that does not work for inline functions, because it is called after RTL for the function has been copied. The pseudo-reg in embedded_pic_fnaddr_rtx however does not get copied, and ends up not matching the rest of the RTL. This solution works, but means that we get unnecessary code to initialize this value every time a function is inlined into another function. */ start_sequence (); emit_insn (gen_get_fnaddr (cfun->machine->embedded_pic_fnaddr_rtx, XEXP (DECL_RTL (current_function_decl), 0))); seq = get_insns (); end_sequence (); push_topmost_sequence (); emit_insn_after (seq, get_insns ()); pop_topmost_sequence (); } return cfun->machine->embedded_pic_fnaddr_rtx;}/* Return RTL for the offset from the current function to the argument. X is the symbol whose offset from the current function we want. */rtxembedded_pic_offset (x) rtx x;{ /* Make sure it is emitted. */ embedded_pic_fnaddr_reg (); return gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, x, XEXP (DECL_RTL (current_function_decl), 0)));}/* Return the appropriate instructions to move one operand to another. */const char *mips_move_1word (operands, insn, unsignedp) rtx operands[]; rtx insn; int unsignedp;{ const char *ret = 0; rtx op0 = operands[0]; rtx op1 = operands[1]; enum rtx_code code0 = GET_CODE (op0); enum rtx_code code1 = GET_CODE (op1); enum machine_mode mode = GET_MODE (op0); 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); } 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); } /* For our purposes, a condition code mode is the same as SImode. */ if (mode == CCmode) mode = SImode; 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 (GP_REG_P (regno0)) { if (GP_REG_P (regno1)) ret = "move\t%0,%1"; else if (MD_REG_P (regno1)) { delay = DELAY_HILO; if (regno1 != HILO_REGNUM) ret = "mf%1\t%0"; else ret = "mflo\t%0"; } else if (ST_REG_P (regno1) && ISA_HAS_8CC) ret = "li\t%0,1\n\tmovf\t%0,%.,%1"; else { delay = DELAY_LOAD; if (FP_REG_P (regno1)) ret = "mfc1\t%0,%1"; else if (ALL_COP_REG_P (regno1)) { static char retval[] = "mfc_\t%0,%1"; retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1); ret = retval; } else if (regno1 == FPSW_REGNUM && ! ISA_HAS_8CC) ret = "cfc1\t%0,$31"; } } else if (FP_REG_P (regno0)) { if (GP_REG_P (regno1)) { delay = DELAY_LOAD; ret = "mtc1\t%1,%0"; } if (FP_REG_P (regno1)) 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 (ALL_COP_REG_P (regno0)) { if (GP_REG_P (regno1)) { static char retval[] = "mtc_\t%1,%0"; char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0); if (cop == '0') abort_with_insn (insn, "mtc0 not supported; it disturbs virtual address translation"); delay = DELAY_LOAD; retval[3] = cop; ret = retval; } } } 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"; else if (ALL_COP_REG_P (regno0)) { static char retval[] = "lwc_\t%0,%1"; char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0); if (cop == '0') abort_with_insn (insn, "loads from memory to COP0 are illegal"); delay = DELAY_LOAD; retval[3] = cop; ret = retval; } 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)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -