📄 arm.c
字号:
& 0xffffffff); rtx new_source; rtx shift = GEN_INT (clear_sign_bit_copies); if ((remainder | shift_mask) != 0xffffffff) { new_source = subtargets ? gen_reg_rtx (mode) : target; insns = arm_split_constant (AND, mode, remainder | shift_mask, new_source, source, subtargets); source = new_source; } new_source = subtargets ? gen_reg_rtx (mode) : target; emit_insn (gen_ashlsi3 (new_source, source, shift)); emit_insn (gen_lshrsi3 (target, new_source, shift)); return insns + 2; } if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24) { HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1; rtx new_source; rtx shift = GEN_INT (clear_zero_bit_copies); if ((remainder | shift_mask) != 0xffffffff) { new_source = subtargets ? gen_reg_rtx (mode) : target; insns = arm_split_constant (AND, mode, remainder | shift_mask, new_source, source, subtargets); source = new_source; } new_source = subtargets ? gen_reg_rtx (mode) : target; emit_insn (gen_lshrsi3 (new_source, source, shift)); emit_insn (gen_ashlsi3 (target, new_source, shift)); return insns + 2; } break; default: break; } for (i = 0; i < 32; i++) if (remainder & (1 << i)) num_bits_set++; if (code == AND || (can_invert && num_bits_set > 16)) remainder = (~remainder) & 0xffffffff; else if (code == PLUS && num_bits_set > 16) remainder = (-remainder) & 0xffffffff; else { can_invert = 0; can_negate = 0; } /* Now try and find a way of doing the job in either two or three instructions. We start by looking for the largest block of zeros that are aligned on a 2-bit boundary, we then fill up the temps, wrapping around to the top of the word when we drop off the bottom. In the worst case this code should produce no more than four insns. */ { int best_start = 0; int best_consecutive_zeros = 0; for (i = 0; i < 32; i += 2) { int consecutive_zeros = 0; if (! (remainder & (3 << i))) { while ((i < 32) && ! (remainder & (3 << i))) { consecutive_zeros += 2; i += 2; } if (consecutive_zeros > best_consecutive_zeros) { best_consecutive_zeros = consecutive_zeros; best_start = i - consecutive_zeros; } i -= 2; } } /* Now start emitting the insns, starting with the one with the highest bit set: we do this so that the smallest number will be emitted last; this is more likely to be combinable with addressing insns. */ i = best_start; do { int end; if (i <= 0) i += 32; if (remainder & (3 << (i - 2))) { end = i - 8; if (end < 0) end += 32; temp1 = remainder & ((0x0ff << end) | ((i < end) ? (0xff >> (32 - end)) : 0)); remainder &= ~temp1; if (code == SET) { emit_insn (gen_rtx (SET, VOIDmode, new_src = (subtargets ? gen_reg_rtx (mode) : target), GEN_INT (can_invert ? ~temp1 : temp1))); can_invert = 0; code = PLUS; } else if (code == MINUS) { emit_insn (gen_rtx (SET, VOIDmode, new_src = (subtargets ? gen_reg_rtx (mode) : target), gen_rtx (code, mode, GEN_INT (temp1), source))); code = PLUS; } else { emit_insn (gen_rtx (SET, VOIDmode, new_src = remainder ? (subtargets ? gen_reg_rtx (mode) : target) : target, gen_rtx (code, mode, source, GEN_INT (can_invert ? ~temp1 : (can_negate ? -temp1 : temp1))))); } insns++; source = new_src; i -= 6; } i -= 2; } while (remainder); } return insns;}#define REG_OR_SUBREG_REG(X) \ (GET_CODE (X) == REG \ || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))#define REG_OR_SUBREG_RTX(X) \ (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))#define ARM_FRAME_RTX(X) \ ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ || (X) == arg_pointer_rtx)intarm_rtx_costs (x, code, outer_code) rtx x; enum rtx_code code, outer_code;{ enum machine_mode mode = GET_MODE (x); enum rtx_code subcode; int extra_cost; switch (code) { case MEM: /* Memory costs quite a lot for the first word, but subsequent words load at the equivalent of a single insn each. */ return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0)); case DIV: case MOD: return 100; case ROTATE: if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG) return 4; /* Fall through */ case ROTATERT: if (mode != SImode) return 8; /* Fall through */ case ASHIFT: case LSHIFTRT: case ASHIFTRT: if (mode == DImode) return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8) + ((GET_CODE (XEXP (x, 0)) == REG || (GET_CODE (XEXP (x, 0)) == SUBREG && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) ? 0 : 8)); return (1 + ((GET_CODE (XEXP (x, 0)) == REG || (GET_CODE (XEXP (x, 0)) == SUBREG && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) ? 0 : 4) + ((GET_CODE (XEXP (x, 1)) == REG || (GET_CODE (XEXP (x, 1)) == SUBREG && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG) || (GET_CODE (XEXP (x, 1)) == CONST_INT)) ? 0 : 4)); case MINUS: if (mode == DImode) return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8) + ((REG_OR_SUBREG_REG (XEXP (x, 0)) || (GET_CODE (XEXP (x, 0)) == CONST_INT && const_ok_for_arm (INTVAL (XEXP (x, 0))))) ? 0 : 8)); if (GET_MODE_CLASS (mode) == MODE_FLOAT) return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1)) || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) ? 0 : 8) + ((REG_OR_SUBREG_REG (XEXP (x, 0)) || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE && const_double_rtx_ok_for_fpu (XEXP (x, 0)))) ? 0 : 8)); if (((GET_CODE (XEXP (x, 0)) == CONST_INT && const_ok_for_arm (INTVAL (XEXP (x, 0))) && REG_OR_SUBREG_REG (XEXP (x, 1)))) || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT || subcode == ASHIFTRT || subcode == LSHIFTRT || subcode == ROTATE || subcode == ROTATERT || (subcode == MULT && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT && ((INTVAL (XEXP (XEXP (x, 1), 1)) & (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0))) && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0)) && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1)) || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT) && REG_OR_SUBREG_REG (XEXP (x, 0)))) return 1; /* Fall through */ case PLUS: if (GET_MODE_CLASS (mode) == MODE_FLOAT) return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) + ((REG_OR_SUBREG_REG (XEXP (x, 1)) || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) ? 0 : 8)); /* Fall through */ case AND: case XOR: case IOR: extra_cost = 0; /* Normally the frame registers will be spilt into reg+const during reload, so it is a bad idea to combine them with other instructions, since then they might not be moved outside of loops. As a compromise we allow integration with ops that have a constant as their second operand. */ if ((REG_OR_SUBREG_REG (XEXP (x, 0)) && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))) && GET_CODE (XEXP (x, 1)) != CONST_INT) || (REG_OR_SUBREG_REG (XEXP (x, 0)) && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))))) extra_cost = 4; if (mode == DImode) return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) + ((REG_OR_SUBREG_REG (XEXP (x, 1)) || (GET_CODE (XEXP (x, 1)) == CONST_INT && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) ? 0 : 8)); if (REG_OR_SUBREG_REG (XEXP (x, 0))) return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost) + ((REG_OR_SUBREG_REG (XEXP (x, 1)) || (GET_CODE (XEXP (x, 1)) == CONST_INT && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) ? 0 : 4)); else if (REG_OR_SUBREG_REG (XEXP (x, 1))) return (1 + extra_cost + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT || subcode == LSHIFTRT || subcode == ASHIFTRT || subcode == ROTATE || subcode == ROTATERT || (subcode == MULT && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && ((INTVAL (XEXP (XEXP (x, 0), 1)) & (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)) && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0))) && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1))) || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) ? 0 : 4)); return 8; case MULT: if (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode) return 30; if (GET_CODE (XEXP (x, 1)) == CONST_INT) { HOST_WIDE_INT i = INTVAL (XEXP (x, 1)) & 0xffffffff; int add_cost = const_ok_for_arm (i) ? 4 : 8; int j; /* This will need adjusting for ARM's with fast multiplies */ for (j = 0; i && j < 32; j += 2) { i &= ~(3 << j); add_cost += 2; } return add_cost; } return (30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4) + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4)); 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; }} /* This code has been fixed for cross compilation. */static int fpa_consts_inited = 0;char *strings_fpa[8] = { "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0" };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)...). */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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -