📄 mn10300.c
字号:
t = build1 (INDIRECT_REF, ptr, t); TREE_SIDE_EFFECTS (t) = 1; } else { t = build1 (NOP_EXPR, ptr, t); TREE_SIDE_EFFECTS (t) = 1; } /* Calculate! */ return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);}/* Return an RTX to represent where a value with mode MODE will be returned from a function. If the result is 0, the argument is pushed. */rtxfunction_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named ATTRIBUTE_UNUSED;{ rtx result = 0; int size, align; /* We only support using 2 data registers as argument registers. */ int nregs = 2; /* Figure out the size of the object to be passed. */ if (mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); /* Figure out the alignment of the object to be passed. */ align = size; cum->nbytes = (cum->nbytes + 3) & ~3; /* Don't pass this arg via a register if all the argument registers are used up. */ if (cum->nbytes > nregs * UNITS_PER_WORD) return 0; /* Don't pass this arg via a register if it would be split between registers and memory. */ if (type == NULL_TREE && cum->nbytes + size > nregs * UNITS_PER_WORD) return 0; switch (cum->nbytes / UNITS_PER_WORD) { case 0: result = gen_rtx_REG (mode, 0); break; case 1: result = gen_rtx_REG (mode, 1); break; default: result = 0; } return result;}/* Return the number of registers to use for an argument passed partially in registers and partially in memory. */intfunction_arg_partial_nregs (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named ATTRIBUTE_UNUSED;{ int size, align; /* We only support using 2 data registers as argument registers. */ int nregs = 2; /* Figure out the size of the object to be passed. */ if (mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); /* Figure out the alignment of the object to be passed. */ align = size; cum->nbytes = (cum->nbytes + 3) & ~3; /* Don't pass this arg via a register if all the argument registers are used up. */ if (cum->nbytes > nregs * UNITS_PER_WORD) return 0; if (cum->nbytes + size <= nregs * UNITS_PER_WORD) return 0; /* Don't pass this arg via a register if it would be split between registers and memory. */ if (type == NULL_TREE && cum->nbytes + size > nregs * UNITS_PER_WORD) return 0; return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD;}/* Output a tst insn. */const char *output_tst (operand, insn) rtx operand, 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 (op, mode) 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 (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 256);}/* 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 (len, bit) int len; int bit;{ 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 (op, mode) 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 (x, oldx, mode) rtx x; rtx oldx ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED;{ /* 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 (GET_CODE (y), Pmode, regx1, regy2)); return force_reg (Pmode, gen_rtx_PLUS (Pmode, regx1, regy1)); } } return x;}intmn10300_address_cost (x, unsig) rtx x; int *unsig;{ int _s = 0; if (unsig == 0) unsig = &_s; 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: return 3; case NO_REGS: return 5; default: abort (); } case PLUS: case MINUS: case ASHIFT: case AND: case IOR: return (mn10300_address_cost (XEXP (x, 0), unsig) + mn10300_address_cost (XEXP (x, 1), unsig)); case EXPR_LIST: case SUBREG: case MEM: return ADDRESS_COST (XEXP (x, 0)); case ZERO_EXTEND: *unsig = 1; return mn10300_address_cost (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; case ADDRESSOF: switch (GET_CODE (XEXP (x, 0))) { case MEM: return ADDRESS_COST (XEXP (x, 0)); case REG: return 1; default: abort (); } default: abort (); }}/* 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 (operands) 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -