📄 mn10300.c
字号:
registers and memory. */ if (type == NULL_TREE && cum->nbytes + size > nregs * UNITS_PER_WORD) return 0; return nregs * UNITS_PER_WORD - cum->nbytes;}/* Output a tst insn. */const char *output_tst (rtx operand, rtx insn){ rtx temp; int past_call = 0; /* We can save a byte if we can find a register which has the value zero in it. */ temp = PREV_INSN (insn); while (optimize && temp) { rtx set; /* We allow the search to go through call insns. We record the fact that we've past a CALL_INSN and reject matches which use call clobbered registers. */ if (GET_CODE (temp) == CODE_LABEL || GET_CODE (temp) == JUMP_INSN || GET_CODE (temp) == BARRIER) break; if (GET_CODE (temp) == CALL_INSN) past_call = 1; if (GET_CODE (temp) == NOTE) { temp = PREV_INSN (temp); continue; } /* It must be an insn, see if it is a simple set. */ set = single_set (temp); if (!set) { temp = PREV_INSN (temp); continue; } /* Are we setting a data register to zero (this does not win for address registers)? If it's a call clobbered register, have we past a call? Make sure the register we find isn't the same as ourself; the mn10300 can't encode that. ??? reg_set_between_p return nonzero anytime we pass a CALL_INSN so the code to detect calls here isn't doing anything useful. */ if (REG_P (SET_DEST (set)) && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) && !reg_set_between_p (SET_DEST (set), temp, insn) && (REGNO_REG_CLASS (REGNO (SET_DEST (set))) == REGNO_REG_CLASS (REGNO (operand))) && REGNO_REG_CLASS (REGNO (SET_DEST (set))) != EXTENDED_REGS && REGNO (SET_DEST (set)) != REGNO (operand) && (!past_call || !call_used_regs[REGNO (SET_DEST (set))])) { rtx xoperands[2]; xoperands[0] = operand; xoperands[1] = SET_DEST (set); output_asm_insn ("cmp %1,%0", xoperands); return ""; } if (REGNO_REG_CLASS (REGNO (operand)) == EXTENDED_REGS && REG_P (SET_DEST (set)) && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) && !reg_set_between_p (SET_DEST (set), temp, insn) && (REGNO_REG_CLASS (REGNO (SET_DEST (set))) != REGNO_REG_CLASS (REGNO (operand))) && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == EXTENDED_REGS && REGNO (SET_DEST (set)) != REGNO (operand) && (!past_call || !call_used_regs[REGNO (SET_DEST (set))])) { rtx xoperands[2]; xoperands[0] = operand; xoperands[1] = SET_DEST (set); output_asm_insn ("cmp %1,%0", xoperands); return ""; } temp = PREV_INSN (temp); } return "cmp 0,%0";}intimpossible_plus_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ if (GET_CODE (op) != PLUS) return 0; if (XEXP (op, 0) == stack_pointer_rtx || XEXP (op, 1) == stack_pointer_rtx) return 1; return 0;}/* Return 1 if X is a CONST_INT that is only 8 bits wide. This is used for the btst insn which may examine memory or a register (the memory variant only allows an unsigned 8 bit integer). */intconst_8bit_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 256);}/* Return true if the operand is the 1.0f constant. */intconst_1f_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (op == CONST1_RTX (SFmode));}/* Similarly, but when using a zero_extract pattern for a btst where the source operand might end up in memory. */intmask_ok_for_mem_btst (int len, int bit){ unsigned int mask = 0; while (len > 0) { mask |= (1 << bit); bit++; len--; } /* MASK must bit into an 8bit value. */ return (((mask & 0xff) == mask) || ((mask & 0xff00) == mask) || ((mask & 0xff0000) == mask) || ((mask & 0xff000000) == mask));}/* Return 1 if X contains a symbolic expression. We know these expressions will have one of a few well defined forms, so we need only check those forms. */intsymbolic_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ switch (GET_CODE (op)) { case SYMBOL_REF: case LABEL_REF: return 1; case CONST: op = XEXP (op, 0); return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF || GET_CODE (XEXP (op, 0)) == LABEL_REF) && GET_CODE (XEXP (op, 1)) == CONST_INT); default: return 0; }}/* Try machine dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new valid address. This macro is used in only one place: `memory_address' in explow.c. OLDX is the address as it was before break_out_memory_refs was called. In some cases it is useful to look at this to decide what needs to be done. MODE and WIN are passed so that this macro can use GO_IF_LEGITIMATE_ADDRESS. Normally it is always safe for this macro to do nothing. It exists to recognize opportunities to optimize the output. But on a few ports with segmented architectures and indexed addressing (mn10300, hppa) it is used to rewrite certain problematical addresses. */rtxlegitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED){ if (flag_pic && ! legitimate_pic_operand_p (x)) x = legitimize_pic_address (oldx, NULL_RTX); /* Uh-oh. We might have an address for x[n-100000]. This needs special handling to avoid creating an indexed memory address with x-100000 as the base. */ if (GET_CODE (x) == PLUS && symbolic_operand (XEXP (x, 1), VOIDmode)) { /* Ugly. We modify things here so that the address offset specified by the index expression is computed first, then added to x to form the entire address. */ rtx regx1, regy1, regy2, y; /* Strip off any CONST. */ y = XEXP (x, 1); if (GET_CODE (y) == CONST) y = XEXP (y, 0); if (GET_CODE (y) == PLUS || GET_CODE (y) == MINUS) { regx1 = force_reg (Pmode, force_operand (XEXP (x, 0), 0)); regy1 = force_reg (Pmode, force_operand (XEXP (y, 0), 0)); regy2 = force_reg (Pmode, force_operand (XEXP (y, 1), 0)); regx1 = force_reg (Pmode, gen_rtx_fmt_ee (GET_CODE (y), Pmode, regx1, regy2)); return force_reg (Pmode, gen_rtx_PLUS (Pmode, regx1, regy1)); } } return x;}/* Convert a non-PIC address in `orig' to a PIC address using @GOT or @GOTOFF in `reg'. */rtxlegitimize_pic_address (rtx orig, rtx reg){ if (GET_CODE (orig) == LABEL_REF || (GET_CODE (orig) == SYMBOL_REF && (CONSTANT_POOL_ADDRESS_P (orig) || ! MN10300_GLOBAL_P (orig)))) { if (reg == 0) reg = gen_reg_rtx (Pmode); emit_insn (gen_symGOTOFF2reg (reg, orig)); return reg; } else if (GET_CODE (orig) == SYMBOL_REF) { if (reg == 0) reg = gen_reg_rtx (Pmode); emit_insn (gen_symGOT2reg (reg, orig)); return reg; } return orig;}/* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol isn't protected by a PIC unspec; nonzero otherwise. */intlegitimate_pic_operand_p (rtx x){ register const char *fmt; register int i; if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) return 0; if (GET_CODE (x) == UNSPEC && (XINT (x, 1) == UNSPEC_PIC || XINT (x, 1) == UNSPEC_GOT || XINT (x, 1) == UNSPEC_GOTOFF || XINT (x, 1) == UNSPEC_PLT)) return 1; fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { if (fmt[i] == 'E') { register int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) if (! legitimate_pic_operand_p (XVECEXP (x, i, j))) return 0; } else if (fmt[i] == 'e' && ! legitimate_pic_operand_p (XEXP (x, i))) return 0; } return 1;}/* Return TRUE if the address X, taken from a (MEM:MODE X) rtx, is legitimate, and FALSE otherwise. */boollegitimate_address_p (enum machine_mode mode, rtx x, int strict){ if (CONSTANT_ADDRESS_P (x) && (! flag_pic || legitimate_pic_operand_p (x))) return TRUE; if (RTX_OK_FOR_BASE_P (x, strict)) return TRUE; if (TARGET_AM33 && GET_CODE (x) == POST_INC && RTX_OK_FOR_BASE_P (XEXP (x, 0), strict) && (mode == SImode || mode == SFmode || mode == HImode)) return TRUE; if (GET_CODE (x) == PLUS) { rtx base = 0, index = 0; if (REG_P (XEXP (x, 0)) && REGNO_STRICT_OK_FOR_BASE_P (REGNO (XEXP (x, 0)), strict)) { base = XEXP (x, 0); index = XEXP (x, 1); } if (REG_P (XEXP (x, 1)) && REGNO_STRICT_OK_FOR_BASE_P (REGNO (XEXP (x, 1)), strict)) { base = XEXP (x, 1); index = XEXP (x, 0); } if (base != 0 && index != 0) { if (GET_CODE (index) == CONST_INT) return TRUE; if (GET_CODE (index) == CONST && GET_CODE (XEXP (index, 0)) != PLUS && (! flag_pic || legitimate_pic_operand_p (index))) return TRUE; } } return FALSE;}static intmn10300_address_cost_1 (rtx x, int *unsig){ switch (GET_CODE (x)) { case REG: switch (REGNO_REG_CLASS (REGNO (x))) { case SP_REGS: *unsig = 1; return 0; case ADDRESS_REGS: return 1; case DATA_REGS: case EXTENDED_REGS: case FP_REGS: return 3; case NO_REGS: return 5; default: abort (); } case PLUS: case MINUS: case ASHIFT: case AND: case IOR: return (mn10300_address_cost_1 (XEXP (x, 0), unsig) + mn10300_address_cost_1 (XEXP (x, 1), unsig)); case EXPR_LIST: case SUBREG: case MEM: return mn10300_address_cost (XEXP (x, 0)); case ZERO_EXTEND: *unsig = 1; return mn10300_address_cost_1 (XEXP (x, 0), unsig); case CONST_INT: if (INTVAL (x) == 0) return 0; if (INTVAL (x) + (*unsig ? 0 : 0x80) < 0x100) return 1; if (INTVAL (x) + (*unsig ? 0 : 0x8000) < 0x10000) return 3; if (INTVAL (x) + (*unsig ? 0 : 0x800000) < 0x1000000) return 5; return 7; case CONST: case SYMBOL_REF: case LABEL_REF: return 8; default: abort (); }}static intmn10300_address_cost (rtx x){ int s = 0; return mn10300_address_cost_1 (x, &s);}static boolmn10300_rtx_costs (rtx x, int code, int outer_code, int *total){ switch (code) { case CONST_INT: /* Zeros are extremely cheap. */ if (INTVAL (x) == 0 && outer_code == SET) *total = 0; /* If it fits in 8 bits, then it's still relatively cheap. */ else if (INT_8_BITS (INTVAL (x))) *total = 1; /* This is the "base" cost, includes constants where either the upper or lower 16bits are all zeros. */ else if (INT_16_BITS (INTVAL (x)) || (INTVAL (x) & 0xffff) == 0 || (INTVAL (x) & 0xffff0000) == 0) *total = 2; else *total = 4; return true; case CONST: case LABEL_REF: case SYMBOL_REF: /* These are more costly than a CONST_INT, but we can relax them, so they're less costly than a CONST_DOUBLE. */ *total = 6; return true; case CONST_DOUBLE: /* We don't optimize CONST_DOUBLEs well nor do we relax them well, so their cost is very high. */ *total = 8; return true; /* ??? This probably needs more work. */ case MOD: case DIV: case MULT: *total = 8; return true; default: return false; }}/* Check whether a constant used to initialize a DImode or DFmode can use a clr instruction. The code here must be kept in sync with movdf and movdi. */boolmn10300_wide_const_load_uses_clr (rtx operands[2]){ long val[2]; if (GET_CODE (operands[0]) != REG || REGNO_REG_CLASS (REGNO (operands[0])) != DATA_REGS) return false; switch (GET_CODE (operands[1])) { case CONST_INT: { rtx low, high; split_double (operands[1], &low, &high); val[0] = INTVAL (low); val[1] = INTVAL (high); } break; case CONST_DOUBLE: if (GET_MODE (operands[1]) == DFmode) { REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); REAL_VALUE_TO_TARGET_DOUBLE (rv, val); } else if (GET_MODE (operands[1]) == VOIDmode || GET_MODE (operands[1]) == DImode) { val[0] = CONST_DOUBLE_LOW (operands[1]); val[1] = CONST_DOUBLE_HIGH (operands[1]); } break; default: return false; } return val[0] == 0 || val[1] == 0;}/* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we may access it using GOTOFF instead of GOT. */static voidmn10300_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED){ rtx symbol; if (GET_CODE (rtl) != MEM) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; if (flag_pic) SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -