📄 iq2000.c
字号:
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); fancy_abort (__FILE__, __LINE__, __FUNCTION__);}/* 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: return SYMBOL_REF_FLAG (addr) ? 1 : 2; case PLUS: { rtx plus0 = XEXP (addr, 0); 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)) { case CONST_INT: return SMALL_INT (plus1) ? 1 : 2; case CONST: case SYMBOL_REF: case LABEL_REF: case HIGH: case LO_SUM: return iq2000_address_cost (plus1) + 1; default: break; } } default: break; } return 4;}/* Make normal rtx_code into something we can index from an array. */static enum internal_testmap_test_to_internal_test (enum rtx_code test_code){ enum internal_test test = ITEST_MAX; switch (test_code) { 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; default: break; } return test;}/* Generate the code to do a TEST_CODE comparison on two integer values CMP0 and CMP1. P_INVERT is NULL or ptr if branch needs to reverse its test. The return value RESULT is: (reg:SI xx) The pseudo register the comparison is in 0 No register, generate a simple branch. */rtxgen_int_relational (enum rtx_code test_code, rtx result, rtx cmp0, rtx cmp1, int *p_invert){ 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 */ { LT, -32769, 32766, 1, 1, 0, 1, 0 }, /* LE */ { LTU, -32769, 32766, 1, 1, 1, 0, 1 }, /* GTU */ { LTU, -32768, 32767, 0, 0, 1, 1, 1 }, /* GEU */ { LTU, -32768, 32767, 0, 0, 0, 0, 1 }, /* LTU */ { LTU, -32769, 32766, 1, 1, 0, 1, 1 }, /* LEU */ }; enum internal_test test; enum machine_mode mode; struct cmp_info *p_info; int branch_p; int eqne_p; int invert; rtx reg; rtx reg2; test = map_test_to_internal_test (test_code); gcc_assert (test != ITEST_MAX); p_info = &info[(int) test]; eqne_p = (p_info->test_code == XOR); mode = GET_MODE (cmp0); if (mode == VOIDmode) mode = GET_MODE (cmp1); /* Eliminate simple branches. */ branch_p = (result == 0); if (branch_p) { if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG) { /* Comparisons against zero are simple branches. */ if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) return 0; /* Test for beq/bne. */ if (eqne_p) return 0; } /* Allocate a pseudo to calculate the value in. */ result = gen_reg_rtx (mode); } /* Make sure we can handle any constants given to us. */ if (GET_CODE (cmp0) == CONST_INT) cmp0 = force_reg (mode, cmp0); if (GET_CODE (cmp1) == CONST_INT) { HOST_WIDE_INT value = INTVAL (cmp1); if (value < p_info->const_low || value > p_info->const_high) cmp1 = force_reg (mode, cmp1); } /* See if we need to invert the result. */ invert = (GET_CODE (cmp1) == CONST_INT ? p_info->invert_const : p_info->invert_reg); if (p_invert != (int *)0) { *p_invert = invert; invert = 0; } /* Comparison to constants, may involve adding 1 to change a LT into LE. Comparison between two registers, may involve switching operands. */ if (GET_CODE (cmp1) == CONST_INT) { if (p_info->const_add != 0) { HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; /* If modification of cmp1 caused overflow, we would get the wrong answer if we follow the usual path; thus, x > 0xffffffffU would turn into x > 0U. */ if ((p_info->unsignedp ? (unsigned HOST_WIDE_INT) new > (unsigned HOST_WIDE_INT) INTVAL (cmp1) : new > INTVAL (cmp1)) != (p_info->const_add > 0)) { /* This test is always true, but if INVERT is true then the result of the test needs to be inverted so 0 should be returned instead. */ emit_move_insn (result, invert ? const0_rtx : const_true_rtx); return result; } else cmp1 = GEN_INT (new);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -