📄 arm.c
字号:
? 0 : 4)); return 8; case MULT: /* There is no point basing this on the tuning, since it is always the fast variant if it exists at all */ if (arm_fast_multiply && mode == DImode && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1))) && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)) return 8; if (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode) return 30; if (GET_CODE (XEXP (x, 1)) == CONST_INT) { unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1)) & (unsigned HOST_WIDE_INT) 0xffffffff); int add_cost = const_ok_for_arm (i) ? 4 : 8; int j; /* Tune as appropriate */ int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2); for (j = 0; i && j < 32; j += booth_unit_size) { i >>= booth_unit_size; add_cost += 2; } return add_cost; } return (((tune_flags & FL_FAST_MULT) ? 8 : 30) + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4) + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4)); case TRUNCATE: if (arm_fast_multiply && mode == SImode && GET_CODE (XEXP (x, 0)) == LSHIFTRT && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1))) && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND)) return 8; return 99; case NEG: if (GET_MODE_CLASS (mode) == MODE_FLOAT) return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6); /* Fall through */ case NOT: if (mode == DImode) return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); case IF_THEN_ELSE: if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) return 14; return 2; case COMPARE: return 1; case ABS: return 4 + (mode == DImode ? 4 : 0); case SIGN_EXTEND: if (GET_MODE (XEXP (x, 0)) == QImode) return (4 + (mode == DImode ? 4 : 0) + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); /* Fall through */ case ZERO_EXTEND: switch (GET_MODE (XEXP (x, 0))) { case QImode: return (1 + (mode == DImode ? 4 : 0) + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); case HImode: return (4 + (mode == DImode ? 4 : 0) + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); case SImode: return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); } abort (); default: return 99; }}intarm_adjust_cost (insn, link, dep, cost) rtx insn; rtx link; rtx dep; int cost;{ rtx i_pat, d_pat; if ((i_pat = single_set (insn)) != NULL && GET_CODE (SET_SRC (i_pat)) == MEM && (d_pat = single_set (dep)) != NULL && GET_CODE (SET_DEST (d_pat)) == MEM) { /* This is a load after a store, there is no conflict if the load reads from a cached area. Assume that loads from the stack, and from the constant pool are cached, and that others will miss. This is a hack. */ /* debug_rtx (insn); debug_rtx (dep); debug_rtx (link); fprintf (stderr, "costs %d\n", cost); */ if (CONSTANT_POOL_ADDRESS_P (XEXP (SET_SRC (i_pat), 0)) || reg_mentioned_p (stack_pointer_rtx, XEXP (SET_SRC (i_pat), 0)) || reg_mentioned_p (frame_pointer_rtx, XEXP (SET_SRC (i_pat), 0)) || reg_mentioned_p (hard_frame_pointer_rtx, XEXP (SET_SRC (i_pat), 0))) {/* fprintf (stderr, "***** Now 1\n"); */ return 1; } } return cost;}/* This code has been fixed for cross compilation. */static int fpa_consts_inited = 0;char *strings_fpa[8] = { "0", "1", "2", "3", "4", "5", "0.5", "10"};static REAL_VALUE_TYPE values_fpa[8];static voidinit_fpa_table (){ int i; REAL_VALUE_TYPE r; for (i = 0; i < 8; i++) { r = REAL_VALUE_ATOF (strings_fpa[i], DFmode); values_fpa[i] = r; } fpa_consts_inited = 1;}/* Return TRUE if rtx X is a valid immediate FPU constant. */intconst_double_rtx_ok_for_fpu (x) rtx x;{ REAL_VALUE_TYPE r; int i; if (!fpa_consts_inited) init_fpa_table (); REAL_VALUE_FROM_CONST_DOUBLE (r, x); if (REAL_VALUE_MINUS_ZERO (r)) return 0; for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (r, values_fpa[i])) return 1; return 0;}/* Return TRUE if rtx X is a valid immediate FPU constant. */intneg_const_double_rtx_ok_for_fpu (x) rtx x;{ REAL_VALUE_TYPE r; int i; if (!fpa_consts_inited) init_fpa_table (); REAL_VALUE_FROM_CONST_DOUBLE (r, x); r = REAL_VALUE_NEGATE (r); if (REAL_VALUE_MINUS_ZERO (r)) return 0; for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (r, values_fpa[i])) return 1; return 0;}/* Predicates for `match_operand' and `match_operator'. *//* s_register_operand is the same as register_operand, but it doesn't accept (SUBREG (MEM)...). This function exists because at the time it was put in it led to better code. SUBREG(MEM) always needs a reload in the places where s_register_operand is used, and this seemed to lead to excessive reloading. */ints_register_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); /* We don't consider registers whose class is NO_REGS to be a register operand. */ return (GET_CODE (op) == REG && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));}/* Only accept reg, subreg(reg), const_int. */intreg_or_int_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return 1; if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); /* We don't consider registers whose class is NO_REGS to be a register operand. */ return (GET_CODE (op) == REG && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));}/* Return 1 if OP is an item in memory, given that we are in reload. */intreload_memory_operand (op, mode) rtx op; enum machine_mode mode;{ int regno = true_regnum (op); return (! CONSTANT_P (op) && (regno == -1 || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)));}/* Return TRUE for valid operands for the rhs of an ARM instruction. */intarm_rhs_operand (op, mode) rtx op; enum machine_mode mode;{ return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));}/* Return TRUE for valid operands for the rhs of an ARM instruction, or a load. */intarm_rhsm_operand (op, mode) rtx op; enum machine_mode mode;{ return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))) || memory_operand (op, mode));}/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a constant that is valid when negated. */intarm_add_operand (op, mode) rtx op; enum machine_mode mode;{ return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && (const_ok_for_arm (INTVAL (op)) || const_ok_for_arm (-INTVAL (op)))));}intarm_not_operand (op, mode) rtx op; enum machine_mode mode;{ return (s_register_operand (op, mode) || (GET_CODE (op) == CONST_INT && (const_ok_for_arm (INTVAL (op)) || const_ok_for_arm (~INTVAL (op)))));}/* Return TRUE if the operand is a memory reference which contains an offsettable address. */intoffsettable_memory_operand (op, mode) register rtx op; enum machine_mode mode;{ if (mode == VOIDmode) mode = GET_MODE (op); return (mode == GET_MODE (op) && GET_CODE (op) == MEM && offsettable_address_p (reload_completed | reload_in_progress, mode, XEXP (op, 0)));}/* Return TRUE if the operand is a memory reference which is, or can be made word aligned by adjusting the offset. */intalignable_memory_operand (op, mode) register rtx op; enum machine_mode mode;{ rtx reg; if (mode == VOIDmode) mode = GET_MODE (op); if (mode != GET_MODE (op) || GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); return ((GET_CODE (reg = op) == REG || (GET_CODE (op) == SUBREG && GET_CODE (reg = SUBREG_REG (op)) == REG) || (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT && (GET_CODE (reg = XEXP (op, 0)) == REG || (GET_CODE (XEXP (op, 0)) == SUBREG && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG)))) && REGNO_POINTER_ALIGN (REGNO (reg)) >= 4);}/* Similar to s_register_operand, but does not allow hard integer registers. */intf_register_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); /* We don't consider registers whose class is NO_REGS to be a register operand. */ return (GET_CODE (op) == REG && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) == FPU_REGS));}/* Return TRUE for valid operands for the rhs of an FPU instruction. */intfpu_rhs_operand (op, mode) rtx op; enum machine_mode mode;{ if (s_register_operand (op, mode)) return TRUE; else if (GET_CODE (op) == CONST_DOUBLE) return (const_double_rtx_ok_for_fpu (op)); return FALSE;}intfpu_add_operand (op, mode) rtx op; enum machine_mode mode;{ if (s_register_operand (op, mode)) return TRUE; else if (GET_CODE (op) == CONST_DOUBLE) return (const_double_rtx_ok_for_fpu (op) || neg_const_double_rtx_ok_for_fpu (op)); return FALSE;}/* Return nonzero if OP is a constant power of two. */intpower_of_two_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT value = INTVAL(op); return value != 0 && (value & (value - 1)) == 0; } return FALSE;}/* Return TRUE for a valid operand of a DImode operation. Either: REG, CONST_DOUBLE or MEM(DImode_address). Note that this disallows MEM(REG+REG), but allows MEM(PRE/POST_INC/DEC(REG)). */intdi_operand (op, mode) rtx op; enum machine_mode mode;{ if (s_register_operand (op, mode)) return TRUE; switch (GET_CODE (op)) { case CONST_DOUBLE: case CONST_INT: return TRUE; case MEM: return memory_address_p (DImode, XEXP (op, 0)); default: return FALSE; }}/* Return TRUE for a valid operand of a DFmode operation when -msoft-float. Either: REG, CONST_DOUBLE or MEM(DImode_address). Note that this disallows MEM(REG+REG), but allows MEM(PRE/POST_INC/DEC(REG)). */intsoft_df_operand (op, mode) rtx op; enum machine_mode mode;{ if (s_register_operand (op, mode)) return TRUE; switch (GET_CODE (op)) { case CONST_DOUBLE: return TRUE; case MEM: return memory_address_p (DFmode, XEXP (op, 0)); default: return FALSE; }}/* Return TRUE for valid index operands. */intindex_operand (op, mode) rtx op; enum machine_mode mode;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -