📄 v850.c
字号:
off_name = "zdaoff"; reg_name = "r0"; } else if (SDA_NAME_P (name)) { off_name = "sdaoff"; reg_name = "gp"; } else if (TDA_NAME_P (name)) { off_name = "tdaoff"; reg_name = "ep"; } else abort(); fprintf (file, "%s(", off_name); output_addr_const (file, addr); fprintf (file, ")[%s]", reg_name); } else output_addr_const (file, addr); break; case CONST: if (special_symbolref_operand (addr, VOIDmode)) { char* name = XSTR (XEXP (XEXP (addr, 0), 0), 0); char* off_name; char* reg_name; if (ZDA_NAME_P (name)) { off_name = "zdaoff"; reg_name = "r0"; } else if (SDA_NAME_P (name)) { off_name = "sdaoff"; reg_name = "gp"; } else if (TDA_NAME_P (name)) { off_name = "tdaoff"; reg_name = "ep"; } else abort(); fprintf (file, "%s(", off_name); output_addr_const (file, addr); fprintf (file, ")[%s]", reg_name); } else output_addr_const (file, addr); break; default: output_addr_const (file, addr); break; }}/* Return appropriate code to load up a 1, 2, or 4 integer/floating point value. */char *output_move_single (operands) rtx *operands;{ rtx dst = operands[0]; rtx src = operands[1]; if (REG_P (dst)) { if (REG_P (src)) return "mov %1,%0"; else if (GET_CODE (src) == CONST_INT) { HOST_WIDE_INT value = INTVAL (src); if (CONST_OK_FOR_J (value)) /* signed 5 bit immediate */ return "mov %1,%0"; else if (CONST_OK_FOR_K (value)) /* signed 16 bit immediate */ return "movea lo(%1),%.,%0"; else if (CONST_OK_FOR_L (value)) /* upper 16 bits were set */ return "movhi hi(%1),%.,%0"; else /* random constant */ return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0"; } else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode) { HOST_WIDE_INT high, low; const_double_split (src, &high, &low); if (CONST_OK_FOR_J (high)) /* signed 5 bit immediate */ return "mov %F1,%0"; else if (CONST_OK_FOR_K (high)) /* signed 16 bit immediate */ return "movea lo(%F1),%.,%0"; else if (CONST_OK_FOR_L (high)) /* upper 16 bits were set */ return "movhi hi(%F1),%.,%0"; else /* random constant */ return "movhi hi(%F1),%.,%0\n\tmovea lo(%F1),%0,%0"; } else if (GET_CODE (src) == MEM) return "%S1ld%W1 %1,%0"; else if (special_symbolref_operand (src, VOIDmode)) return "movea %O1(%P1),%Q1,%0"; else if (GET_CODE (src) == LABEL_REF || GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST) { return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0"; } else if (GET_CODE (src) == HIGH) return "movhi hi(%1),%.,%0"; else if (GET_CODE (src) == LO_SUM) { operands[2] = XEXP (src, 0); operands[3] = XEXP (src, 1); return "movea lo(%3),%2,%0"; } } else if (GET_CODE (dst) == MEM) { if (REG_P (src)) return "%S0st%W0 %1,%0"; else if (GET_CODE (src) == CONST_INT && INTVAL (src) == 0) return "%S0st%W0 %.,%0"; else if (GET_CODE (src) == CONST_DOUBLE && CONST0_RTX (GET_MODE (dst)) == src) return "%S0st%W0 %.,%0"; } fatal_insn ("output_move_single:", gen_rtx (SET, VOIDmode, dst, src)); return "";}/* Return appropriate code to load up an 8 byte integer or floating point value */char *output_move_double (operands) rtx *operands;{ enum machine_mode mode = GET_MODE (operands[0]); rtx dst = operands[0]; rtx src = operands[1]; if (register_operand (dst, mode) && register_operand (src, mode)) { if (REGNO (src) + 1 == REGNO (dst)) return "mov %R1,%R0\n\tmov %1,%0"; else return "mov %1,%0\n\tmov %R1,%R0"; } /* Storing 0 */ if (GET_CODE (dst) == MEM && ((GET_CODE (src) == CONST_INT && INTVAL (src) == 0) || (GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src)))) return "st.w %.,%0\n\tst.w %.,%R0"; if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE) { HOST_WIDE_INT high_low[2]; int i; rtx xop[10]; if (GET_CODE (src) == CONST_DOUBLE) const_double_split (src, &high_low[1], &high_low[0]); else { high_low[0] = INTVAL (src); high_low[1] = (INTVAL (src) >= 0) ? 0 : -1; } for (i = 0; i < 2; i++) { xop[0] = gen_rtx (REG, SImode, REGNO (dst)+i); xop[1] = GEN_INT (high_low[i]); output_asm_insn (output_move_single (xop), xop); } return ""; } if (GET_CODE (src) == MEM) { int ptrreg = -1; int dreg = REGNO (dst); rtx inside = XEXP (src, 0); if (GET_CODE (inside) == REG) ptrreg = REGNO (inside); else if (GET_CODE (inside) == SUBREG) ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside); else if (GET_CODE (inside) == PLUS) ptrreg = REGNO (XEXP (inside, 0)); else if (GET_CODE (inside) == LO_SUM) ptrreg = REGNO (XEXP (inside, 0)); if (dreg == ptrreg) return "ld.w %R1,%R0\n\tld.w %1,%0"; } if (GET_CODE (src) == MEM) return "ld.w %1,%0\n\tld.w %R1,%R0"; if (GET_CODE (dst) == MEM) return "st.w %1,%0\n\tst.w %R1,%R0"; return "mov %1,%0\n\tmov %R1,%R0";}/* Return maximum offset supported for a short EP memory reference of mode MODE and signedness UNSIGNEDP. */intep_memory_offset (mode, unsignedp) enum machine_mode mode; int unsignedp;{ int max_offset = 0; switch (mode) { case QImode: max_offset = (1 << 7); break; case HImode: max_offset = (1 << 8); break; case SImode: case SFmode: max_offset = (1 << 8); break; } return max_offset;}/* Return true if OP is a valid short EP memory reference */intep_memory_operand (op, mode, unsigned_load) rtx op; enum machine_mode mode; int unsigned_load;{ rtx addr, op0, op1; int max_offset; int mask; 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 TDA_NAME_P (XSTR (addr, 0)); 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) & mask) == 0) { if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM) return TRUE; if (GET_CODE (op0) == SYMBOL_REF && TDA_NAME_P (XSTR (op0, 0))) return TRUE; } break; } return FALSE;}/* Return true if OP is either a register or 0 */intreg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return INTVAL (op) == 0; else if (GET_CODE (op) == CONST_DOUBLE) return CONST_DOUBLE_OK_FOR_G (op); else return register_operand (op, mode);}/* Return true if OP is either a register or a signed five bit integer */intreg_or_int5_operand (op, mode) rtx op; 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 a valid call operand. */intcall_address_operand (op, mode) rtx op; enum machine_mode 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 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) == 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 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; int i; 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 p_mem = (rtx *)0; if (p_mem) { rtx addr = XEXP (*p_mem, 0); if (GET_CODE (addr) == REG && REGNO (addr) == 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)) == regno && GET_CODE (XEXP (addr, 1)) == CONST_INT && (((unsigned)INTVAL (XEXP (addr, 1))) < ep_memory_offset (GET_MODE (*p_mem), unsignedp))) *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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -