📄 arm.c
字号:
rtx to; int up; int write_back;{ int i = 0, j; rtx result; int sign = up ? 1 : -1; result = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (count + (write_back ? 2 : 0))); if (write_back) { XVECEXP (result, 0, 0) = gen_rtx (SET, GET_MODE (to), to, plus_constant (to, count * 4 * sign)); i = 1; count++; } for (j = 0; i < count; i++, j++) { XVECEXP (result, 0, i) = gen_rtx (SET, VOIDmode, gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)), gen_rtx (REG, SImode, base_regno + j)); } if (write_back) XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to); return result;}intarm_gen_movstrqi (operands) rtx *operands;{ HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes; int i, r; rtx src, dst; rtx st_src, st_dst, end_src, end_dst, fin_src, fin_dst; rtx part_bytes_reg = NULL; extern int optimize; if (GET_CODE (operands[2]) != CONST_INT || GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[2]) > 64 || INTVAL (operands[3]) & 3) return 0; st_dst = XEXP (operands[0], 0); st_src = XEXP (operands[1], 0); fin_dst = dst = copy_to_mode_reg (SImode, st_dst); fin_src = src = copy_to_mode_reg (SImode, st_src); in_words_to_go = (INTVAL (operands[2]) + 3) / 4; out_words_to_go = INTVAL (operands[2]) / 4; last_bytes = INTVAL (operands[2]) & 3; if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0) part_bytes_reg = gen_rtx (REG, SImode, (in_words_to_go - 1) & 3); for (i = 0; in_words_to_go >= 2; i+=4) { emit_insn (arm_gen_load_multiple (0, (in_words_to_go > 4 ? 4 : in_words_to_go), src, TRUE, TRUE)); if (out_words_to_go) { if (out_words_to_go != 1) emit_insn (arm_gen_store_multiple (0, (out_words_to_go > 4 ? 4 : out_words_to_go), dst, TRUE, TRUE)); else { emit_move_insn (gen_rtx (MEM, SImode, dst), gen_rtx (REG, SImode, 0)); emit_insn (gen_addsi3 (dst, dst, GEN_INT (4))); } } in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4; out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4; } /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do. */ if (out_words_to_go) { rtx sreg; emit_move_insn (sreg = gen_reg_rtx (SImode), gen_rtx (MEM, SImode, src)); emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4)); emit_move_insn (gen_rtx (MEM, SImode, dst), sreg); emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4)); in_words_to_go--; if (in_words_to_go) /* Sanity check */ abort (); } if (in_words_to_go) { if (in_words_to_go < 0) abort (); part_bytes_reg = copy_to_mode_reg (SImode, gen_rtx (MEM, SImode, src)); emit_insn (gen_addsi3 (src, src, GEN_INT (4))); } if (BYTES_BIG_ENDIAN && last_bytes) { rtx tmp = gen_reg_rtx (SImode); if (part_bytes_reg == NULL) abort (); /* The bytes we want are in the top end of the word */ emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8 * (4 - last_bytes)))); part_bytes_reg = tmp; while (last_bytes) { emit_move_insn (gen_rtx (MEM, QImode, plus_constant (dst, last_bytes - 1)), gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); if (--last_bytes) { tmp = gen_reg_rtx (SImode); emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); part_bytes_reg = tmp; } } } else { while (last_bytes) { if (part_bytes_reg == NULL) abort (); emit_move_insn (gen_rtx (MEM, QImode, dst), gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); emit_insn (gen_addsi3 (dst, dst, const1_rtx)); if (--last_bytes) { rtx tmp = gen_reg_rtx (SImode); emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); part_bytes_reg = tmp; } } } return 1;}/* X and Y are two things to compare using CODE. Emit the compare insn and return the rtx for register 0 in the proper mode. FP means this is a floating point compare: I don't think that it is needed on the arm. */rtxgen_compare_reg (code, x, y, fp) enum rtx_code code; rtx x, y;{ enum machine_mode mode = SELECT_CC_MODE (code, x, y); rtx cc_reg = gen_rtx (REG, mode, 24); emit_insn (gen_rtx (SET, VOIDmode, cc_reg, gen_rtx (COMPARE, mode, x, y))); return cc_reg;}voidarm_reload_in_hi (operands) rtx *operands;{ rtx base = find_replacement (&XEXP (operands[1], 0)); emit_insn (gen_zero_extendqisi2 (operands[2], gen_rtx (MEM, QImode, base))); emit_insn (gen_zero_extendqisi2 (gen_rtx (SUBREG, SImode, operands[0], 0), gen_rtx (MEM, QImode, plus_constant (base, 1)))); if (BYTES_BIG_ENDIAN) emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, operands[0], 0), gen_rtx (IOR, SImode, gen_rtx (ASHIFT, SImode, gen_rtx (SUBREG, SImode, operands[0], 0), GEN_INT (8)), operands[2]))); else emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, operands[0], 0), gen_rtx (IOR, SImode, gen_rtx (ASHIFT, SImode, operands[2], GEN_INT (8)), gen_rtx (SUBREG, SImode, operands[0], 0))));}voidarm_reload_out_hi (operands) rtx *operands;{ rtx base = find_replacement (&XEXP (operands[0], 0)); if (BYTES_BIG_ENDIAN) { emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), gen_rtx (SUBREG, QImode, operands[1], 0))); emit_insn (gen_lshrsi3 (operands[2], gen_rtx (SUBREG, SImode, operands[1], 0), GEN_INT (8))); emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), gen_rtx (SUBREG, QImode, operands[2], 0))); } else { emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), gen_rtx (SUBREG, QImode, operands[1], 0))); emit_insn (gen_lshrsi3 (operands[2], gen_rtx (SUBREG, SImode, operands[1], 0), GEN_INT (8))); emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), gen_rtx (SUBREG, QImode, operands[2], 0))); }}/* Check to see if a branch is forwards or backwards. Return TRUE if it is backwards. */intarm_backwards_branch (from, to) int from, to;{ return insn_addresses[to] <= insn_addresses[from];}/* Check to see if a branch is within the distance that can be done using an arithmetic expression. */intshort_branch (from, to) int from, to;{ int delta = insn_addresses[from] + 8 - insn_addresses[to]; return abs (delta) < 980; /* A small margin for safety */}/* Check to see that the insn isn't the target of the conditionalizing code */intarm_insn_not_targeted (insn) rtx insn;{ return insn != arm_target_insn;}/* Routines to output assembly language. *//* If the rtx is the correct value then return the string of the number. In this way we can ensure that valid double constants are generated even when cross compiling. */char *fp_immediate_constant (x) rtx x;{ REAL_VALUE_TYPE r; int i; if (!fpa_consts_inited) init_fpa_table (); REAL_VALUE_FROM_CONST_DOUBLE (r, x); for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (r, values_fpa[i])) return strings_fpa[i]; abort ();}/* As for fp_immediate_constant, but value is passed directly, not in rtx. */static char *fp_const_from_val (r) REAL_VALUE_TYPE *r;{ int i; if (! fpa_consts_inited) init_fpa_table (); for (i = 0; i < 8; i++) if (REAL_VALUES_EQUAL (*r, values_fpa[i])) return strings_fpa[i]; abort ();}/* Output the operands of a LDM/STM instruction to STREAM. MASK is the ARM register set mask of which only bits 0-15 are important. INSTR is the possibly suffixed base register. HAT unequals zero if a hat must follow the register list. */voidprint_multi_reg (stream, instr, mask, hat) FILE *stream; char *instr; int mask, hat;{ int i; int not_first = FALSE; fputc ('\t', stream); fprintf (stream, instr, REGISTER_PREFIX); fputs (", {", stream); for (i = 0; i < 16; i++) if (mask & (1 << i)) { if (not_first) fprintf (stream, ", "); fprintf (stream, "%s%s", REGISTER_PREFIX, reg_names[i]); not_first = TRUE; } fprintf (stream, "}%s\n", hat ? "^" : "");}/* Output a 'call' insn. */char *output_call (operands) rtx *operands;{ /* Handle calls to lr using ip (which may be clobbered in subr anyway). */ if (REGNO (operands[0]) == 14) { operands[0] = gen_rtx (REG, SImode, 12); output_asm_insn ("mov%?\t%0, %|lr", operands); } output_asm_insn ("mov%?\t%|lr, %|pc", operands); output_asm_insn ("mov%?\t%|pc, %0", operands); return "";}static inteliminate_lr2ip (x) rtx *x;{ int something_changed = 0; rtx x0 = *x; int code = GET_CODE (x0); register int i, j; register char *fmt; switch (code) { case REG: if (REGNO (x0) == 14) { *x = gen_rtx (REG, SImode, 12); return 1; } return 0; default: /* Scan through the sub-elements and change any references there */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') something_changed |= eliminate_lr2ip (&XEXP (x0, i)); else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x0, i); j++) something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j)); return something_changed; }} /* Output a 'call' insn that is a reference in memory. */char *output_call_mem (operands) rtx *operands;{ operands[0] = copy_rtx (operands[0]); /* Be ultra careful */ /* Handle calls using lr by using ip (which may be clobbered in subr anyway). */ if (eliminate_lr2ip (&operands[0])) output_asm_insn ("mov%?\t%|ip, %|lr", operands); output_asm_insn ("mov%?\t%|lr, %|pc", operands); output_asm_insn ("ldr%?\t%|pc, %0", operands); return "";}/* Output a move from arm registers to an fpu registers. OPERANDS[0] is an fpu register. OPERANDS[1] is the first registers of an arm register pair. */char *output_mov_long_double_fpu_from_arm (operands) rtx *operands;{ int arm_reg0 = REGNO (operands[1]); rtx ops[3]; if (arm_reg0 == 12) abort(); ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops); output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands); return "";}/* Output a move from an fpu register to arm registers. OPERANDS[0] is the first registers of an arm register pair. OPERANDS[1] is an fpu register. */char *output_mov_long_double_arm_from_fpu (operands) rtx *operands;{ int arm_reg0 = REGNO (operands[0]); rtx ops[3]; if (arm_reg0 == 12) abort(); ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands); output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops); return "";}/* Output a move from arm registers to arm registers of a long double OPERANDS[0] is the destination. OPERANDS[1] is the source. */char *output_mov_long_double_arm_from_arm (operands) rtx *operands;{ /* We have to be careful here because the two might overlap */ int dest_start = REGNO (operands[0]); int src_start = REGNO (operands[1]); rtx ops[2]; int i; if (dest_start < src_start) { for (i = 0; i < 3; i++) { ops[0] = gen_rtx (REG, SImode, dest_start + i); ops[1] = gen_rtx (REG, SImode, src_start + i); output_asm_insn ("mov%?\t%0, %1", ops); } } else { for (i = 2; i >= 0; i--) { ops[0] = gen_rtx (REG, SImode, dest_start + i); ops[1] = gen_rtx (REG, SImode, src_start + i); output_asm_insn ("mov%?\t%0, %1", ops); } } return "";}/* Output a move from arm registers to an fpu registers. OPERANDS[0] is an fpu register. OPERANDS[1] is the first registers of an arm register pair. */char *output_mov_double_fpu_from_arm (operands) rtx *operands;{ int arm_reg0 = REGNO (operands[1]); rtx ops[2]; if (arm_reg0 == 12) abort(); ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops); output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands); return "";}/* Output a move from an fpu register to arm registers. OPERANDS[0] is the first registers of an arm register pair. OPERANDS[1] is an fpu register. */char *output_mov_double_arm_from_fpu (operands) rtx *operands;{ int arm_reg0 = REGNO (operands[0]); rtx ops[2]; if (arm_reg0 == 12) abort(); ops[0] = gen_rtx (REG, SImode, arm_reg0); ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands); output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops); return "";}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -