📄 mips.c
字号:
intm16_nsimm5_1 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, - 0xf, 0x10, 0);}intm16_uimm5_4 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, (- 0x10) << 2, 0xf << 2, 3);}intm16_nuimm5_4 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, (- 0xf) << 2, 0x10 << 2, 3);}intm16_simm8_1 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, - 0x80, 0x7f, 0);}intm16_nsimm8_1 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, - 0x7f, 0x80, 0);}intm16_uimm8_1 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, 0x0, 0xff, 0);}intm16_nuimm8_1 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, - 0xff, 0x0, 0);}intm16_uimm8_m1_1 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, - 0x1, 0xfe, 0);}intm16_uimm8_4 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, 0x0, 0xff << 2, 3);}intm16_nuimm8_4 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, (- 0xff) << 2, 0x0, 3);}intm16_simm8_8 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, (- 0x80) << 3, 0x7f << 3, 7);}intm16_nsimm8_8 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);}/* References to the string table on the mips16 only use a small offset if the function is small. See the comment in the SYMBOL_REF case in simple_memory_operand. We can't check for LABEL_REF here, because the offset is always large if the label is before the referencing instruction. */intm16_usym8_4 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op) && current_frame_info.insns_len > 0 && XSTR (op, 0)[0] == '*' && strncmp (XSTR (op, 0) + 1, LOCAL_LABEL_PREFIX, sizeof LOCAL_LABEL_PREFIX - 1) == 0 && (current_frame_info.insns_len + get_pool_size () + mips_string_length < 4 * 0x100)) { struct string_constant *l; /* Make sure this symbol is on thelist of string constants to be output for this function. It is possible that it has already been output, in which case this requires a large offset. */ for (l = string_constants; l != NULL; l = l->next) if (strcmp (l->label, XSTR (op, 0)) == 0) return 1; } return 0;}intm16_usym5_4 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op) && current_frame_info.insns_len > 0 && XSTR (op, 0)[0] == '*' && strncmp (XSTR (op, 0) + 1, LOCAL_LABEL_PREFIX, sizeof LOCAL_LABEL_PREFIX - 1) == 0 && (current_frame_info.insns_len + get_pool_size () + mips_string_length < 4 * 0x20)) { struct string_constant *l; /* Make sure this symbol is on thelist of string constants to be output for this function. It is possible that it has already been output, in which case this requires a large offset. */ for (l = string_constants; l != NULL; l = l->next) if (strcmp (l->label, XSTR (op, 0)) == 0) return 1; } return 0;}/* Returns an operand string for the given instruction's delay slot, after updating filled delay slot statistics. We assume that operands[0] is the target register that is set. In order to check the next insn, most of this functionality is moved to FINAL_PRESCAN_INSN, and we just set the global variables that it needs. *//* ??? This function no longer does anything useful, because final_prescan_insn now will never emit a nop. */const char *mips_fill_delay_slot (ret, type, operands, cur_insn) const char *ret; /* normal string to return */ enum delay_type type; /* type of delay */ rtx operands[]; /* operands to use */ rtx cur_insn; /* current insn */{ register rtx set_reg; register enum machine_mode mode; register rtx next_insn = cur_insn ? NEXT_INSN (cur_insn) : NULL_RTX; register int num_nops; 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 RTL for the offset from the current function to the argument. ??? Which argument is this? */rtxembedded_pic_offset (x) rtx x;{ if (embedded_pic_fnaddr_rtx == NULL) { rtx seq; 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 (embedded_pic_fnaddr_rtx, XEXP (DECL_RTL (current_function_decl), 0))); seq = gen_sequence (); end_sequence (); push_topmost_sequence (); emit_insn_after (seq, get_insns ()); pop_topmost_sequence (); } 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 (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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -