📄 iq2000.c
字号:
xlow0 = SUBREG_REG (xlow0); if (GET_CODE (xlow0) == REG && iq2000_reg_mode_ok_for_base_p (xlow0, mode, strict) && iq2000_check_split (xlow1, mode)) return 1; } if (GET_CODE (xinsn) == PLUS) { rtx xplus0 = XEXP (xinsn, 0); rtx xplus1 = XEXP (xinsn, 1); enum rtx_code code0; enum rtx_code code1; while (GET_CODE (xplus0) == SUBREG) xplus0 = SUBREG_REG (xplus0); code0 = GET_CODE (xplus0); while (GET_CODE (xplus1) == SUBREG) xplus1 = SUBREG_REG (xplus1); code1 = GET_CODE (xplus1); if (code0 == REG && iq2000_reg_mode_ok_for_base_p (xplus0, mode, strict)) { if (code1 == CONST_INT && SMALL_INT (xplus1) && SMALL_INT_UNSIGNED (xplus1) /* No negative offsets */) return 1; } } if (TARGET_DEBUG_A_MODE) GO_PRINTF ("Not a legitimate address\n"); /* The address was not legitimate. */ 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. */const char *iq2000_fill_delay_slot (const char *ret, enum delay_type type, rtx operands[], rtx cur_insn){ rtx set_reg; enum machine_mode mode; rtx next_insn = cur_insn ? NEXT_INSN (cur_insn) : NULL_RTX; int num_nops; if (type == DELAY_LOAD || type == DELAY_FCMP) num_nops = 1; 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 || GET_CODE (next_insn) == CODE_LABEL)) next_insn = NEXT_INSN (next_insn); dslots_load_total += num_nops; if (TARGET_DEBUG_C_MODE || 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; iq2000_load_reg = 0; iq2000_load_reg2 = 0; iq2000_load_reg3 = 0; iq2000_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; iq2000_load_reg = set_reg; if (GET_MODE_SIZE (mode) > (unsigned) (UNITS_PER_WORD)) iq2000_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1); else iq2000_load_reg2 = 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. */static voidiq2000_count_memory_refs (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========== iq2000_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;}/* Abort after printing out a specific insn. */static voidabort_with_insn (rtx insn, const char * reason){ error (reason); debug_rtx (insn); abort ();}/* Return the appropriate instructions to move one operand to another. */const char *iq2000_move_1word (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; /* Do not do anything for assigning a register to itself */ if (regno0 == regno1) ret = ""; else if (GP_REG_P (regno0)) { if (GP_REG_P (regno1)) ret = "or\t%0,%%0,%1"; } } else if (code1 == MEM) { delay = DELAY_LOAD; if (TARGET_STATS) iq2000_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 = "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 (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) { if (GP_REG_P (regno0)) ret = "or\t%0,%%0,%z1"; } else if (GP_REG_P (regno0)) { if (SMALL_INT_UNSIGNED (op1)) ret = "ori\t%0,%%0,%x1\t\t\t# %1"; else if (SMALL_INT (op1)) ret = "addiu\t%0,%%0,%1\t\t\t# %1"; else ret = "lui\t%0,%X1\t\t\t# %1\n\tori\t%0,%0,%x1"; } } else if (code1 == CONST_DOUBLE && mode == SFmode) { if (op1 == CONST0_RTX (SFmode)) { if (GP_REG_P (regno0)) ret = "or\t%0,%%0,%."; } else { delay = DELAY_LOAD; ret = "li.s\t%0,%1"; } } else if (code1 == LABEL_REF) { if (TARGET_STATS) iq2000_count_memory_refs (op1, 1); ret = "la\t%0,%a1"; } else if (code1 == SYMBOL_REF || code1 == CONST) { if (TARGET_STATS) iq2000_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) iq2000_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 (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) { abort_with_insn (insn, "Bad move"); return 0; } if (delay != DELAY_NONE) return iq2000_fill_delay_slot (ret, delay, operands, insn); return ret;}/* Provide the costs of an addressing mode that contains ADDR. */static intiq2000_address_cost (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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -