📄 iq2000.c
字号:
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); if (test == ITEST_MAX) abort (); 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); } } else if (p_info->reverse_regs) { rtx temp = cmp0; cmp0 = cmp1; cmp1 = temp; } if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0) reg = cmp0; else { reg = (invert || eqne_p) ? gen_reg_rtx (mode) : result; convert_move (reg, gen_rtx_fmt_ee (p_info->test_code, mode, cmp0, cmp1), 0); } if (test == ITEST_NE) { convert_move (result, gen_rtx_GTU (mode, reg, const0_rtx), 0); if (p_invert != NULL) *p_invert = 0; invert = 0; } else if (test == ITEST_EQ) { reg2 = invert ? gen_reg_rtx (mode) : result; convert_move (reg2, gen_rtx_LTU (mode, reg, const1_rtx), 0); reg = reg2; } if (invert) { rtx one; one = const1_rtx; convert_move (result, gen_rtx_XOR (mode, reg, one), 0); } return result;}/* Emit the common code for doing conditional branches. operand[0] is the label to jump to. The comparison operands are saved away by cmp{si,di,sf,df}. */voidgen_conditional_branch (rtx operands[], enum rtx_code test_code){ enum cmp_type type = branch_type; rtx cmp0 = branch_cmp[0]; rtx cmp1 = branch_cmp[1]; enum machine_mode mode; rtx reg; int invert; rtx label1, label2; switch (type) { case CMP_SI: case CMP_DI: mode = type == CMP_SI ? SImode : DImode; invert = 0; reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert); if (reg) { cmp0 = reg; cmp1 = const0_rtx; test_code = NE; } else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0) /* We don't want to build a comparison against a nonzero constant. */ cmp1 = force_reg (mode, cmp1); break; case CMP_SF: case CMP_DF: reg = gen_reg_rtx (CCmode); /* For cmp0 != cmp1, build cmp0 == cmp1, and test for result == 0. */ emit_insn (gen_rtx_SET (VOIDmode, reg, gen_rtx_fmt_ee (test_code == NE ? EQ : test_code, CCmode, cmp0, cmp1))); test_code = test_code == NE ? EQ : NE; mode = CCmode; cmp0 = reg; cmp1 = const0_rtx; invert = 0; break; default: abort_with_insn (gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1), "bad test"); } /* Generate the branch. */ label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]); label2 = pc_rtx; if (invert) { label2 = label1; label1 = pc_rtx; } emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, gen_rtx_fmt_ee (test_code, mode, cmp0, cmp1), label1, label2)));}/* Initialize CUM for a function FNTYPE. */voidinit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname ATTRIBUTE_UNUSED){ static CUMULATIVE_ARGS zero_cum; tree param; tree next_param; if (TARGET_DEBUG_D_MODE) { fprintf (stderr, "\ninit_cumulative_args, fntype = 0x%.8lx", (long) fntype); if (!fntype) fputc ('\n', stderr); else { tree ret_type = TREE_TYPE (fntype); fprintf (stderr, ", fntype code = %s, ret code = %s\n", tree_code_name[(int)TREE_CODE (fntype)], tree_code_name[(int)TREE_CODE (ret_type)]); } } *cum = zero_cum; /* Determine if this function has variable arguments. This is indicated by the last argument being 'void_type_mode' if there are no variable arguments. The standard IQ2000 calling sequence passes all arguments in the general purpose registers in this case. */ for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0; param != 0; param = next_param) { next_param = TREE_CHAIN (param); if (next_param == 0 && TREE_VALUE (param) != void_type_node) cum->gp_reg_found = 1; }}/* Advance the argument of type TYPE and mode MODE to the next argument position in CUM. */voidfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named){ if (TARGET_DEBUG_D_MODE) { fprintf (stderr, "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, ", cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode)); fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type); fprintf (stderr, ", %d )\n\n", named); } cum->arg_number++; switch (mode) { case VOIDmode: break; default: if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) abort (); cum->gp_reg_found = 1; cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); break; case BLKmode: cum->gp_reg_found = 1; cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); break; case SFmode: cum->arg_words ++; if (! cum->gp_reg_found && cum->arg_number <= 2) cum->fp_code += 1 << ((cum->arg_number - 1) * 2); break; case DFmode: cum->arg_words += 2; if (! cum->gp_reg_found && cum->arg_number <= 2) cum->fp_code += 2 << ((cum->arg_number - 1) * 2); break; case DImode: cum->gp_reg_found = 1; cum->arg_words += 2; break; case QImode: case HImode: case SImode: cum->gp_reg_found = 1; cum->arg_words ++; break; }}/* Return an RTL expression containing the register for the given mode MODE and type TYPE in CUM, or 0 if the argument is to be passed on the stack. */struct rtx_def *function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named){ rtx ret; int regbase = -1; int bias = 0; unsigned int *arg_words = &cum->arg_words; int struct_p = (type != 0 && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE)); if (TARGET_DEBUG_D_MODE) { fprintf (stderr, "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, ", cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode)); fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type); fprintf (stderr, ", %d ) = ", named); } cum->last_arg_fp = 0; switch (mode) { case SFmode: regbase = GP_ARG_FIRST; break; case DFmode: cum->arg_words += cum->arg_words & 1; regbase = GP_ARG_FIRST; break; default: if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) abort (); /* Drops through. */ case BLKmode: if (type != NULL_TREE && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD) cum->arg_words += (cum->arg_words & 1); regbase = GP_ARG_FIRST; break; case VOIDmode: case QImode: case HImode: case SImode: regbase = GP_ARG_FIRST; break; case DImode: cum->arg_words += (cum->arg_words & 1); regbase = GP_ARG_FIRST; } if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS) { if (TARGET_DEBUG_D_MODE) fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : ""); ret = 0; } else { if (regbase == -1) abort (); if (! type || TREE_CODE (type) != RECORD_TYPE || ! named || ! TYPE_SIZE_UNIT (type)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -