📄 v850.c
字号:
max_offset = (1 << 4); else max_offset = (1 << 7); break; case HImode: if (TARGET_SMALL_SLD) max_offset = (1 << 5); else if (TARGET_V850E && ( ( unsignedp && ! TARGET_US_BIT_SET) || (! unsignedp && TARGET_US_BIT_SET))) max_offset = (1 << 5); else max_offset = (1 << 8); break; case SImode: case SFmode: max_offset = (1 << 8); break; default: break; } return max_offset;}/* Return true if OP is a valid short EP memory reference */intep_memory_operand (rtx op, enum machine_mode mode, int unsigned_load){ rtx addr, op0, op1; int max_offset; int mask; /* If we are not using the EP register on a per-function basis then do not allow this optimisation at all. This is to prevent the use of the SLD/SST instructions which cannot be guaranteed to work properly due to a hardware bug. */ if (!TARGET_EP) return FALSE; if (GET_CODE (op) != MEM) return FALSE; max_offset = ep_memory_offset (mode, unsigned_load); mask = GET_MODE_SIZE (mode) - 1; addr = XEXP (op, 0); if (GET_CODE (addr) == CONST) addr = XEXP (addr, 0); switch (GET_CODE (addr)) { default: break; case SYMBOL_REF: return SYMBOL_REF_TDA_P (addr); case REG: return REGNO (addr) == EP_REGNUM; case PLUS: op0 = XEXP (addr, 0); op1 = XEXP (addr, 1); if (GET_CODE (op1) == CONST_INT && INTVAL (op1) < max_offset && INTVAL (op1) >= 0 && (INTVAL (op1) & mask) == 0) { if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM) return TRUE; if (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_TDA_P (op0)) return TRUE; } break; } return FALSE;}/* Substitute memory references involving a pointer, to use the ep pointer, taking care to save and preserve the ep. */static voidsubstitute_ep_register (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);}/* TARGET_MACHINE_DEPENDENT_REORG. On the 850, we use it to implement the -mep mode to copy heavily used pointers to ep to use the implicit addressing. */static voidv850_reorg (void){ 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 = get_insns (); 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 (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 registers that need to be saved. To detect this we note that the helper functions always push at least register r29 (provided that the function is not an interrupt handler). */ if (TARGET_PROLOG_FUNCTION && (i == 2 || ((i >= 20) && (i < 30)))) { if (i == 2) { size += 4; reg_saved |= 1L << i; i = 20; } /* Helper functions save all registers between the starting register and the last register, regardless of whether they are actually used by the function or not. */ for (; i <= 29; i++) { size += 4; reg_saved |= 1L << i; } if (regs_ever_live [LINK_POINTER_REGNUM]) { size += 4; reg_saved |= 1L << LINK_POINTER_REGNUM; } } else { for (; i <= 31; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -