📄 v850.c
字号:
enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return CONST_OK_FOR_J (INTVAL (op)); else return register_operand (op, mode);}/* Return true if OP is either a register or a signed nine bit integer. */intreg_or_int9_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return CONST_OK_FOR_O (INTVAL (op)); return register_operand (op, mode);}/* Return true if OP is either a register or a const integer. */intreg_or_const_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return TRUE; return register_operand (op, mode);}/* Return true if OP is a valid call operand. */intcall_address_operand (op, mode) rtx op; enum machine_mode ATTRIBUTE_UNUSED mode;{ /* Only registers are valid call operands if TARGET_LONG_CALLS. */ if (TARGET_LONG_CALLS) return GET_CODE (op) == REG; return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);}intspecial_symbolref_operand (op, mode) rtx op; enum machine_mode ATTRIBUTE_UNUSED mode;{ if (GET_CODE (op) == SYMBOL_REF) return ENCODED_NAME_P (XSTR (op, 0)); else if (GET_CODE (op) == CONST) return (GET_CODE (XEXP (op, 0)) == PLUS && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF && ENCODED_NAME_P (XSTR (XEXP (XEXP (op, 0), 0), 0)) && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT && CONST_OK_FOR_K (INTVAL (XEXP (XEXP (op, 0), 1)))); return FALSE;}intmovsi_source_operand (op, mode) rtx op; enum machine_mode mode;{ /* Some constants, as well as symbolic operands must be done with HIGH & LO_SUM patterns. */ if (CONSTANT_P (op) && GET_CODE (op) != HIGH && GET_CODE (op) != CONSTANT_P_RTX && !(GET_CODE (op) == CONST_INT && (CONST_OK_FOR_J (INTVAL (op)) || CONST_OK_FOR_K (INTVAL (op)) || CONST_OK_FOR_L (INTVAL (op))))) return special_symbolref_operand (op, mode); else return general_operand (op, mode);}intpower_of_two_operand (op, mode) rtx op; enum machine_mode ATTRIBUTE_UNUSED mode;{ if (GET_CODE (op) != CONST_INT) return 0; if (exact_log2 (INTVAL (op)) == -1) return 0; return 1;}intnot_power_of_two_operand (op, mode) rtx op; enum machine_mode mode;{ unsigned int mask; if (mode == QImode) mask = 0xff; else if (mode == HImode) mask = 0xffff; else if (mode == SImode) mask = 0xffffffff; else return 0; if (GET_CODE (op) != CONST_INT) return 0; if (exact_log2 (~INTVAL (op) & mask) == -1) return 0; return 1;}/* Substitute memory references involving a pointer, to use the ep pointer, taking care to save and preserve the ep. */static voidsubstitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep) rtx first_insn; rtx last_insn; int uses; int regno; rtx *p_r1; rtx *p_ep;{ rtx reg = gen_rtx_REG (Pmode, regno); rtx insn; if (!*p_r1) { regs_ever_live[1] = 1; *p_r1 = gen_rtx_REG (Pmode, 1); *p_ep = gen_rtx_REG (Pmode, 30); } if (TARGET_DEBUG) fprintf (stderr, "\Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n", 2 * (uses - 3), uses, reg_names[regno], IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), INSN_UID (first_insn), INSN_UID (last_insn)); if (GET_CODE (first_insn) == NOTE) first_insn = next_nonnote_insn (first_insn); last_insn = next_nonnote_insn (last_insn); for (insn = first_insn; insn && insn != last_insn; insn = NEXT_INSN (insn)) { if (GET_CODE (insn) == INSN) { rtx pattern = single_set (insn); /* Replace the memory references. */ if (pattern) { rtx *p_mem; /* Memory operands are signed by default. */ int unsignedp = FALSE; if (GET_CODE (SET_DEST (pattern)) == MEM && GET_CODE (SET_SRC (pattern)) == MEM) p_mem = (rtx *)0; else if (GET_CODE (SET_DEST (pattern)) == MEM) p_mem = &SET_DEST (pattern); else if (GET_CODE (SET_SRC (pattern)) == MEM) p_mem = &SET_SRC (pattern); else if (GET_CODE (SET_SRC (pattern)) == SIGN_EXTEND && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM) p_mem = &XEXP (SET_SRC (pattern), 0); else if (GET_CODE (SET_SRC (pattern)) == ZERO_EXTEND && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM) { p_mem = &XEXP (SET_SRC (pattern), 0); unsignedp = TRUE; } else p_mem = (rtx *)0; if (p_mem) { rtx addr = XEXP (*p_mem, 0); if (GET_CODE (addr) == REG && REGNO (addr) == (unsigned) regno) *p_mem = change_address (*p_mem, VOIDmode, *p_ep); else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == REG && REGNO (XEXP (addr, 0)) == (unsigned) regno && GET_CODE (XEXP (addr, 1)) == CONST_INT && ((INTVAL (XEXP (addr, 1))) < ep_memory_offset (GET_MODE (*p_mem), unsignedp)) && ((INTVAL (XEXP (addr, 1))) >= 0)) *p_mem = change_address (*p_mem, VOIDmode, gen_rtx_PLUS (Pmode, *p_ep, XEXP (addr, 1))); } } } } /* Optimize back to back cases of ep <- r1 & r1 <- ep. */ insn = prev_nonnote_insn (first_insn); if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == *p_ep && SET_SRC (PATTERN (insn)) == *p_r1) delete_insn (insn); else emit_insn_before (gen_rtx_SET (Pmode, *p_r1, *p_ep), first_insn); emit_insn_before (gen_rtx_SET (Pmode, *p_ep, reg), first_insn); emit_insn_before (gen_rtx_SET (Pmode, *p_ep, *p_r1), last_insn);}/* In rare cases, correct code generation requires extra machine dependent processing between the second jump optimization pass and delayed branch scheduling. On those machines, define this macro as a C statement to act on the code starting at INSN. On the 850, we use it to implement the -mep mode to copy heavily used pointers to ep to use the implicit addressing. */void v850_reorg (start_insn) rtx start_insn;{ struct { int uses; rtx first_insn; rtx last_insn; } regs[FIRST_PSEUDO_REGISTER]; int i; int use_ep = FALSE; rtx r1 = NULL_RTX; rtx ep = NULL_RTX; rtx insn; rtx pattern; /* If not ep mode, just return now. */ if (!TARGET_EP) return; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { regs[i].uses = 0; regs[i].first_insn = NULL_RTX; regs[i].last_insn = NULL_RTX; } for (insn = start_insn; insn != NULL_RTX; insn = NEXT_INSN (insn)) { switch (GET_CODE (insn)) { /* End of basic block */ default: if (!use_ep) { int max_uses = -1; int max_regno = -1; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (max_uses < regs[i].uses) { max_uses = regs[i].uses; max_regno = i; } } if (max_uses > 3) substitute_ep_register (regs[max_regno].first_insn, regs[max_regno].last_insn, max_uses, max_regno, &r1, &ep); } use_ep = FALSE; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { regs[i].uses = 0; regs[i].first_insn = NULL_RTX; regs[i].last_insn = NULL_RTX; } break; case NOTE: break; case INSN: pattern = single_set (insn); /* See if there are any memory references we can shorten */ if (pattern) { rtx src = SET_SRC (pattern); rtx dest = SET_DEST (pattern); rtx mem; /* Memory operands are signed by default. */ int unsignedp = FALSE; /* We might have (SUBREG (MEM)) here, so just get rid of the subregs to make this code simpler. */ if (GET_CODE (dest) == SUBREG && (GET_CODE (SUBREG_REG (dest)) == MEM || GET_CODE (SUBREG_REG (dest)) == REG)) alter_subreg (&dest); if (GET_CODE (src) == SUBREG && (GET_CODE (SUBREG_REG (src)) == MEM || GET_CODE (SUBREG_REG (src)) == REG)) alter_subreg (&src); if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM) mem = NULL_RTX; else if (GET_CODE (dest) == MEM) mem = dest; else if (GET_CODE (src) == MEM) mem = src; else if (GET_CODE (src) == SIGN_EXTEND && GET_CODE (XEXP (src, 0)) == MEM) mem = XEXP (src, 0); else if (GET_CODE (src) == ZERO_EXTEND && GET_CODE (XEXP (src, 0)) == MEM) { mem = XEXP (src, 0); unsignedp = TRUE; } else mem = NULL_RTX; if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp)) use_ep = TRUE; else if (!use_ep && mem && GET_MODE_SIZE (GET_MODE (mem)) <= UNITS_PER_WORD) { rtx addr = XEXP (mem, 0); int regno = -1; int short_p; if (GET_CODE (addr) == REG) { short_p = TRUE; regno = REGNO (addr); } else if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == REG && GET_CODE (XEXP (addr, 1)) == CONST_INT && ((INTVAL (XEXP (addr, 1))) < ep_memory_offset (GET_MODE (mem), unsignedp)) && ((INTVAL (XEXP (addr, 1))) >= 0)) { short_p = TRUE; regno = REGNO (XEXP (addr, 0)); } else short_p = FALSE; if (short_p) { regs[regno].uses++; regs[regno].last_insn = insn; if (!regs[regno].first_insn) regs[regno].first_insn = insn; } } /* Loading up a register in the basic block zaps any savings for the register */ if (GET_CODE (dest) == REG) { enum machine_mode mode = GET_MODE (dest); int regno; int endregno; regno = REGNO (dest); endregno = regno + HARD_REGNO_NREGS (regno, mode); if (!use_ep) { /* See if we can use the pointer before this modification. */ int max_uses = -1; int max_regno = -1; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (max_uses < regs[i].uses) { max_uses = regs[i].uses; max_regno = i; } } if (max_uses > 3 && max_regno >= regno && max_regno < endregno) { substitute_ep_register (regs[max_regno].first_insn, regs[max_regno].last_insn, max_uses, max_regno, &r1, &ep); /* Since we made a substitution, zap all remembered registers. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { regs[i].uses = 0; regs[i].first_insn = NULL_RTX; regs[i].last_insn = NULL_RTX; } } } for (i = regno; i < endregno; i++) { regs[i].uses = 0; regs[i].first_insn = NULL_RTX; regs[i].last_insn = NULL_RTX; } } } } }}/* # of registers saved by the interrupt handler. */#define INTERRUPT_FIXED_NUM 4/* # of bytes for registers saved by the interrupt handler. */#define INTERRUPT_FIXED_SAVE_SIZE (4 * INTERRUPT_FIXED_NUM)/* # of registers saved in register parameter area. */#define INTERRUPT_REGPARM_NUM 4/* # of words saved for other registers. */#define INTERRUPT_ALL_SAVE_NUM \ (30 - INTERRUPT_FIXED_NUM + INTERRUPT_REGPARM_NUM)#define INTERRUPT_ALL_SAVE_SIZE (4 * INTERRUPT_ALL_SAVE_NUM)intcompute_register_save_size (p_reg_saved) long *p_reg_saved;{ int size = 0; int i; int interrupt_handler = v850_interrupt_function_p (current_function_decl); int call_p = regs_ever_live [LINK_POINTER_REGNUM]; long reg_saved = 0; /* Count the return pointer if we need to save it. */ if (current_function_profile && !call_p) regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1; /* Count space for the register saves. */ if (interrupt_handler) { for (i = 0; i <= 31; i++) switch (i) { default: if (regs_ever_live[i] || call_p) { size += 4; reg_saved |= 1L << i; } break; /* We don't save/restore r0 or the stack pointer */ case 0: case STACK_POINTER_REGNUM: break; /* For registers with fixed use, we save them, set them to the appropriate value, and then restore them. These registers are handled specially, so don't list them on the list of registers to save in the prologue. */ case 1: /* temp used to hold ep */ case 4: /* gp */ case 10: /* temp used to call interrupt save/restore */ case EP_REGNUM: /* ep */ size += 4; break; } } else { /* Find the first register that needs to be saved. */ for (i = 0; i <= 31; i++) if (regs_ever_live[i] && ((! call_used_regs[i]) || i == LINK_POINTER_REGNUM)) break; /* If it is possible that an out-of-line helper function might be used to generate the prologue for the current function, then we need to cover the possibility that such a helper function will be used, despite the fact that there might be gaps in the list of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -