📄 m32r.c
字号:
int must_swap = 0; switch (code) { case EQ: compare_code = EQ; branch_code = NE; break; case NE: compare_code = EQ; branch_code = EQ; break; case LT: compare_code = LT; branch_code = NE; break; case LE: compare_code = LT; branch_code = EQ; must_swap = 1; break; case GT: compare_code = LT; branch_code = NE; must_swap = 1; break; case GE: compare_code = LT; branch_code = EQ; break; case LTU: compare_code = LTU; branch_code = NE; break; case LEU: compare_code = LTU; branch_code = EQ; must_swap = 1; break; case GTU: compare_code = LTU; branch_code = NE; must_swap = 1; break; case GEU: compare_code = LTU; branch_code = EQ; break; } if (need_compare) { switch (compare_code) { case EQ: if (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y)) /* reg equal to small const. */ && y != const0_rtx) { rtx tmp = gen_reg_rtx (SImode); emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y)); x = tmp; y = const0_rtx; } else if (CONSTANT_P (y)) /* reg equal to const. */ { rtx tmp = force_reg (GET_MODE (x), y); y = tmp; } if (register_operand (y, SImode) /* reg equal to reg. */ || y == const0_rtx) /* req equal to zero. */ { emit_insn (gen_cmp_eqsi_insn (x, y)); return gen_rtx (code, mode, cc_reg, const0_rtx); } break; case LT: if (register_operand (y, SImode) || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y)))) { rtx tmp = gen_reg_rtx (SImode); /* reg compared to reg. */ switch (code) { case LT: emit_insn (gen_cmp_ltsi_insn (x, y)); code = EQ; break; case LE: if (y == const0_rtx) tmp = const1_rtx; else emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); emit_insn (gen_cmp_ltsi_insn (x, tmp)); code = EQ; break; case GT: if (GET_CODE (y) == CONST_INT) tmp = gen_rtx (PLUS, SImode, y, const1_rtx); else emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); emit_insn (gen_cmp_ltsi_insn (x, tmp)); code = NE; break; case GE: emit_insn (gen_cmp_ltsi_insn (x, y)); code = NE; break; default: abort(); } return gen_rtx (code, mode, cc_reg, const0_rtx); } break; case LTU: if (register_operand (y, SImode) || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y)))) { rtx tmp = gen_reg_rtx (SImode); /* reg (unsigned) compared to reg. */ switch (code) { case LTU: emit_insn (gen_cmp_ltusi_insn (x, y)); code = EQ; break; case LEU: if (y == const0_rtx) tmp = const1_rtx; else emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); emit_insn (gen_cmp_ltusi_insn (x, tmp)); code = EQ; break; case GTU: if (GET_CODE (y) == CONST_INT) tmp = gen_rtx (PLUS, SImode, y, const1_rtx); else emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); emit_insn (gen_cmp_ltusi_insn (x, tmp)); code = NE; break; case GEU: emit_insn (gen_cmp_ltusi_insn (x, y)); code = NE; break; default: abort(); } return gen_rtx (code, mode, cc_reg, const0_rtx); } break; default: abort(); } } else if (! TARGET_OLD_COMPARE) { /* reg/reg equal comparison */ if (compare_code == EQ && register_operand (y, SImode)) return gen_rtx (code, mode, x, y); /* reg/zero signed comparison */ if ((compare_code == EQ || compare_code == LT) && y == const0_rtx) return gen_rtx (code, mode, x, y); /* reg/smallconst equal comparison */ if (compare_code == EQ && GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))) { rtx tmp = gen_reg_rtx (SImode); emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y)); return gen_rtx (code, mode, tmp, const0_rtx); } /* reg/const equal comparison */ if (compare_code == EQ && CONSTANT_P (y)) { rtx tmp = force_reg (GET_MODE (x), y); return gen_rtx (code, mode, x, tmp); } } if (CONSTANT_P (y)) { if (must_swap) y = force_reg (GET_MODE (x), y); else { int ok_const = (code == LTU || code == LEU || code == GTU || code == GEU) ? uint16_operand (y, GET_MODE (y)) : reg_or_cmp_int16_operand (y, GET_MODE (y)); if (! ok_const) y = force_reg (GET_MODE (x), y); } } switch (compare_code) { case EQ : emit_insn (gen_cmp_eqsi_insn (must_swap ? y : x, must_swap ? x : y)); break; case LT : emit_insn (gen_cmp_ltsi_insn (must_swap ? y : x, must_swap ? x : y)); break; case LTU : emit_insn (gen_cmp_ltusi_insn (must_swap ? y : x, must_swap ? x : y)); break; } return gen_rtx (branch_code, VOIDmode, cc_reg, CONST0_RTX (mode));}/* Split a 2 word move (DI or DF) into component parts. */rtxgen_split_move_double (operands) rtx operands[];{ enum machine_mode mode = GET_MODE (operands[0]); rtx dest = operands[0]; rtx src = operands[1]; rtx val; /* We might have (SUBREG (MEM)) here, so just get rid of the subregs to make this code simpler. It is safe to call alter_subreg any time after reload. */ if (GET_CODE (dest) == SUBREG) dest = alter_subreg (dest); if (GET_CODE (src) == SUBREG) src = alter_subreg (src); start_sequence (); if (GET_CODE (dest) == REG) { int dregno = REGNO (dest); /* reg = reg */ if (GET_CODE (src) == REG) { int sregno = REGNO (src); int reverse = (dregno == sregno + 1); /* We normally copy the low-numbered register first. However, if the first register operand 0 is the same as the second register of operand 1, we must copy in the opposite order. */ emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, reverse, TRUE, mode), operand_subword (src, reverse, TRUE, mode))); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, !reverse, TRUE, mode), operand_subword (src, !reverse, TRUE, mode))); } /* reg = constant */ else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE) { rtx words[2]; split_double (src, &words[0], &words[1]); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 0, TRUE, mode), words[0])); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, 1, TRUE, mode), words[1])); } /* reg = mem */ else if (GET_CODE (src) == MEM) { /* If the high-address word is used in the address, we must load it last. Otherwise, load it first. */ rtx addr = XEXP (src, 0); int reverse = (refers_to_regno_p (dregno, dregno+1, addr, 0) != 0); /* We used to optimize loads from single registers as ld r1,r3+; ld r2,r3 if r3 were not used subsequently. However, the REG_NOTES aren't propigated correctly by the reload phase, and it can cause bad code to be generated. We could still try: ld r1,r3+; ld r2,r3; addi r3,-4 which saves 2 bytes and doesn't force longword alignment. */ emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, reverse, TRUE, mode), change_address (src, SImode, plus_constant (addr, reverse * UNITS_PER_WORD)))); emit_insn (gen_rtx_SET (VOIDmode, operand_subword (dest, !reverse, TRUE, mode), change_address (src, SImode, plus_constant (addr, (!reverse) * UNITS_PER_WORD)))); } else abort (); } /* mem = reg */ /* We used to optimize loads from single registers as st r1,r3; st r2,+r3 if r3 were not used subsequently. However, the REG_NOTES aren't propigated correctly by the reload phase, and it can cause bad code to be generated. We could still try: st r1,r3; st r2,+r3; addi r3,-4 which saves 2 bytes and doesn't force longword alignment. */ else if (GET_CODE (dest) == MEM && GET_CODE (src) == REG) { rtx addr = XEXP (dest, 0); emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, addr), operand_subword (src, 0, TRUE, mode))); emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (addr, UNITS_PER_WORD)), operand_subword (src, 1, TRUE, mode))); } else abort (); val = gen_sequence (); end_sequence (); return val;}/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */intfunction_arg_partial_nregs (cum, int_mode, type, named) CUMULATIVE_ARGS *cum; int int_mode; tree type; int named;{ enum machine_mode mode = (enum machine_mode)int_mode; int ret; int size = (((mode == BLKmode && type) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if (*cum >= M32R_MAX_PARM_REGS) ret = 0; else if (*cum + size > M32R_MAX_PARM_REGS) ret = (*cum + size) - M32R_MAX_PARM_REGS; else ret = 0; return ret;}/* Do any needed setup for a variadic function. For the M32R, we must create a register parameter block, and then copy any anonymous arguments in registers to memory. CUM has not been updated for the last named argument which has type TYPE and mode MODE, and we rely on this fact. */voidm32r_setup_incoming_varargs (cum, int_mode, type, pretend_size, no_rtl) CUMULATIVE_ARGS *cum; int int_mode; tree type; int *pretend_size; int no_rtl;{ enum machine_mode mode = (enum machine_mode)int_mode; int first_anon_arg; if (no_rtl) return; /* All BLKmode values are passed by reference. */ if (mode == BLKmode) abort (); /* We must treat `__builtin_va_alist' as an anonymous arg. */ if (current_function_varargs) first_anon_arg = *cum; else first_anon_arg = (ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type)); if (first_anon_arg < M32R_MAX_PARM_REGS) { /* Note that first_reg_offset < M32R_MAX_PARM_REGS. */ int first_reg_offset = first_anon_arg; /* Size in words to "pretend" allocate. */ int size = M32R_MAX_PARM_REGS - first_reg_offset; rtx regblock; regblock = gen_rtx (MEM, BLKmode, plus_constant (arg_pointer_rtx, FIRST_PARM_OFFSET (0))); move_block_from_reg (first_reg_offset, regblock, size, size * UNITS_PER_WORD); *pretend_size = (size * UNITS_PER_WORD); }}/* Cost functions. *//* Provide the costs of an addressing mode that contains ADDR. If ADDR is not a valid address, its cost is irrelevant. This function is trivial at the moment. This code doesn't live in m32r.h so it's easy to experiment. */intm32r_address_cost (addr) rtx addr;{ return 1;}/* Type of function DECL. The result is cached. To reset the cache at the end of a function, call with DECL = NULL_TREE. */enum m32r_function_typem32r_compute_function_type (decl) tree decl;{ /* Cached value. */ static enum m32r_function_type fn_type = M32R_FUNCTION_UNKNOWN; /* Last function we were called for. */ static tree last_fn = NULL_TREE; /* Resetting the cached value? */ if (decl == NULL_TREE) { fn_type = M32R_FUNCTION_UNKNOWN; last_fn = NULL_TREE; return fn_type; } if (decl == last_fn && fn_type != M32R_FUNCTION_UNKNOWN) return fn_type; /* Compute function type. */ fn_type = (lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE ? M32R_FUNCTION_INTERRUPT : M32R_FUNCTION_NORMAL); last_fn = decl; return fn_type;}/* Function prologue/epilogue handlers. *//* M32R stack frames look like: Before call After call +-----------------------+ +-----------------------+ | | | | high | local variables, | | local variables, | mem | reg save area, etc. | | reg save area, etc. | | | | | +-----------------------+ +-----------------------+ | | | | | arguments on stack. | | arguments on stack. | | | | | SP+0->+-----------------------+ +-----------------------+ | reg parm save area, | | only created for | | variable argument | | functions | +-----------------------+ | previous frame ptr | +-----------------------+ | | | register save area | | | +-----------------------+ | return address | +-----------------------+ | | | local variables |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -