📄 mn10300.c
字号:
{ switch (get_attr_cc (insn)) { case CC_NONE: /* Insn does not affect CC at all. */ break; case CC_NONE_0HIT: /* Insn does not change CC, but the 0'th operand has been changed. */ if (cc_status.value1 != 0 && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) cc_status.value1 = 0; break; case CC_SET_ZN: /* Insn sets the Z,N flags of CC to recog_operand[0]. V,C are unusable. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_CARRY | CC_OVERFLOW_UNUSABLE; cc_status.value1 = recog_operand[0]; break; case CC_SET_ZNV: /* Insn sets the Z,N,V flags of CC to recog_operand[0]. C is unusable. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_CARRY; cc_status.value1 = recog_operand[0]; break; case CC_COMPARE: /* The insn is a compare instruction. */ CC_STATUS_INIT; cc_status.value1 = SET_SRC (body); break; case CC_INVERT: /* The insn is a compare instruction. */ CC_STATUS_INIT; cc_status.value1 = SET_SRC (body); cc_status.flags |= CC_INVERTED; break; case CC_CLOBBER: /* Insn doesn't leave CC in a usable state. */ CC_STATUS_INIT; break; default: abort (); }}/* Return true if OP is a valid call operand. */intcall_address_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);}/* What (if any) secondary registers are needed to move IN with mode MODE into a register from in register class CLASS. We might be able to simplify this. */enum reg_classsecondary_reload_class (class, mode, in) enum reg_class class; enum machine_mode mode; rtx in;{ int regno; /* Memory loads less than a full word wide can't have an address or stack pointer destination. They must use a data register as an intermediate register. */ if (GET_CODE (in) == MEM && (mode == QImode || mode == HImode) && (class == ADDRESS_REGS || class == SP_REGS)) { return DATA_REGS; } /* We can't directly load sp + const_int into a data register; we must use an address register as an intermediate. */ if (class != SP_REGS && class != ADDRESS_REGS && class != SP_OR_ADDRESS_REGS && (in == stack_pointer_rtx || (GET_CODE (in) == PLUS && (XEXP (in, 0) == stack_pointer_rtx || XEXP (in, 1) == stack_pointer_rtx)))) return ADDRESS_REGS; if (GET_CODE (in) == PLUS && (XEXP (in, 0) == stack_pointer_rtx || XEXP (in, 1) == stack_pointer_rtx)) { return DATA_REGS; } /* Otherwise assume no secondary reloads are needed. */ return NO_REGS;}intinitial_offset (from, to) int from, to;{ /* The difference between the argument pointer and the frame pointer is the size of the callee register save area. */ if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) { if (regs_ever_live[2] || regs_ever_live[3] || regs_ever_live[6] || regs_ever_live[7] || frame_pointer_needed) return REG_SAVE_BYTES; else return 0; } /* The difference between the argument pointer and the stack pointer is the sum of the size of this function's frame, the callee register save area, and the fixed stack space needed for function calls (if any). */ if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) { if (regs_ever_live[2] || regs_ever_live[3] || regs_ever_live[6] || regs_ever_live[7] || frame_pointer_needed) return (get_frame_size () + REG_SAVE_BYTES + (current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0)); else return (get_frame_size () + (current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0)); } /* The difference between the frame pointer and stack pointer is the sum of the size of this function's frame and the fixed stack space needed for function calls (if any). */ if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) return (get_frame_size () + (current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0)); abort ();}/* Flush the argument registers to the stack for a stdarg function; return the new argument pointer. */rtxmn10300_builtin_saveregs (arglist) tree arglist;{ rtx offset; tree fntype = TREE_TYPE (current_function_decl); int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))) ? UNITS_PER_WORD : 0); if (argadj) offset = plus_constant (current_function_arg_offset_rtx, argadj); else offset = current_function_arg_offset_rtx; emit_move_insn (gen_rtx (MEM, SImode, current_function_internal_arg_pointer), gen_rtx (REG, SImode, 0)); emit_move_insn (gen_rtx (MEM, SImode, plus_constant (current_function_internal_arg_pointer, 4)), gen_rtx (REG, SImode, 1)); return copy_to_reg (expand_binop (Pmode, add_optab, current_function_internal_arg_pointer, offset, 0, 0, OPTAB_LIB_WIDEN));}/* 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;{ 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;{ 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. */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 (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;{ extern rtx *reg_equiv_mem; rtx reg1, reg2; 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;{ 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;{ 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; enum machine_mode mode;{ /* 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, regx2, 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -