📄 mn10300.c
字号:
we'll be able to save one byte by using rets. */ if (! REG_SAVE_BYTES) this_strategy_size--; if (this_strategy_size < strategy_size) { strategy = restore_a1; strategy_size = this_strategy_size; } } switch (strategy) { case restore_sp_post_adjust: break; case restore_sp_pre_adjust: emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size))); size = 0; break; case restore_sp_partial_adjust: emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size + 4 * num_regs_to_save + REG_SAVE_BYTES - 252))); size = 252 - REG_SAVE_BYTES - 4 * num_regs_to_save; break; case restore_a1: reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM + 1); emit_insn (gen_movsi (reg, stack_pointer_rtx)); if (size) emit_insn (gen_addsi3 (reg, reg, GEN_INT (size))); break; default: abort (); } } /* Adjust the selected register, if any, for post-increment. */ if (reg) reg = gen_rtx_POST_INC (SImode, reg); for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i) if (regs_ever_live[i] && ! call_used_regs[i]) { rtx addr; if (reg) addr = reg; else if (size) { /* If we aren't using a post-increment register, use an SP offset. */ addr = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (size)); } else addr = stack_pointer_rtx; size += 4; emit_insn (gen_movsi (gen_rtx_REG (SImode, i), gen_rtx_MEM (SImode, addr))); } /* If we were using the restore_a1 strategy and the number of bytes to be released won't fit in the `ret' byte, copy `a1' to `sp', to avoid having to use `add' to adjust it. */ if (! frame_pointer_needed && reg && size + REG_SAVE_BYTES > 255) { emit_move_insn (stack_pointer_rtx, XEXP (reg, 0)); size = 0; } } /* Maybe cut back the stack, except for the register save area. If the frame pointer exists, then use the frame pointer to cut back the stack. If the stack size + register save area is more than 255 bytes, then the stack must be cut back here since the size + register save size is too big for a ret/retf instruction. Else leave it alone, it will be cut back as part of the ret/retf instruction, or there wasn't any stack to begin with. Under no circumstances should the register save area be deallocated here, that would leave a window where an interrupt could occur and trash the register save area. */ if (frame_pointer_needed) { emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); size = 0; } else if (size + REG_SAVE_BYTES > 255) { emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size))); size = 0; } /* Adjust the stack and restore callee-saved registers, if any. */ if (size || regs_ever_live[2] || regs_ever_live[3] || regs_ever_live[6] || regs_ever_live[7] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] || frame_pointer_needed) emit_jump_insn (gen_return_internal_regs (GEN_INT (size + REG_SAVE_BYTES))); else emit_jump_insn (gen_return_internal ());}/* Update the condition code from the insn. */voidnotice_update_cc (rtx body, rtx insn){ 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_data.operand[0], cc_status.value1)) cc_status.value1 = 0; break; case CC_SET_ZN: /* Insn sets the Z,N flags of CC to recog_data.operand[0]. V,C are unusable. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_CARRY | CC_OVERFLOW_UNUSABLE; cc_status.value1 = recog_data.operand[0]; break; case CC_SET_ZNV: /* Insn sets the Z,N,V flags of CC to recog_data.operand[0]. C is unusable. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_CARRY; cc_status.value1 = recog_data.operand[0]; break; case CC_COMPARE: /* The insn is a compare instruction. */ CC_STATUS_INIT; cc_status.value1 = SET_SRC (body); if (GET_CODE (cc_status.value1) == COMPARE && GET_MODE (XEXP (cc_status.value1, 0)) == SFmode) cc_status.mdep.fpCC = 1; break; case CC_CLOBBER: /* Insn doesn't leave CC in a usable state. */ CC_STATUS_INIT; break; default: abort (); }}/* Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store(). This function is for MATCH_PARALLEL and so assumes OP is known to be parallel. If OP is a multiple store, return a mask indicating which registers it saves. Return 0 otherwise. */intstore_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ int count; int mask; int i; unsigned int last; rtx elt; count = XVECLEN (op, 0); if (count < 2) return 0; /* Check that first instruction has the form (set (sp) (plus A B)) */ elt = XVECEXP (op, 0, 0); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != REG || REGNO (SET_DEST (elt)) != STACK_POINTER_REGNUM || GET_CODE (SET_SRC (elt)) != PLUS) return 0; /* Check that A is the stack pointer and B is the expected stack size. For OP to match, each subsequent instruction should push a word onto the stack. We therefore expect the first instruction to create COUNT-1 stack slots. */ elt = SET_SRC (elt); if (GET_CODE (XEXP (elt, 0)) != REG || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM || GET_CODE (XEXP (elt, 1)) != CONST_INT || INTVAL (XEXP (elt, 1)) != -(count - 1) * 4) return 0; /* Now go through the rest of the vector elements. They must be ordered so that the first instruction stores the highest-numbered register to the highest stack slot and that subsequent instructions store a lower-numbered register to the slot below. LAST keeps track of the smallest-numbered register stored so far. MASK is the set of stored registers. */ last = LAST_EXTENDED_REGNUM + 1; mask = 0; for (i = 1; i < count; i++) { /* Check that element i is a (set (mem M) R) and that R is valid. */ elt = XVECEXP (op, 0, i); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != MEM || GET_CODE (SET_SRC (elt)) != REG || REGNO (SET_SRC (elt)) >= last) return 0; /* R was OK, so provisionally add it to MASK. We return 0 in any case if the rest of the instruction has a flaw. */ last = REGNO (SET_SRC (elt)); mask |= (1 << last); /* Check that M has the form (plus (sp) (const_int -I*4)) */ elt = XEXP (SET_DEST (elt), 0); if (GET_CODE (elt) != PLUS || GET_CODE (XEXP (elt, 0)) != REG || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM || GET_CODE (XEXP (elt, 1)) != CONST_INT || INTVAL (XEXP (elt, 1)) != -i * 4) return 0; } /* All or none of the callee-saved extended registers must be in the set. */ if ((mask & 0x3c000) != 0 && (mask & 0x3c000) != 0x3c000) return 0; return mask;}/* Return true if OP is a valid call operand. */intcall_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ if (flag_pic) return (EXTRA_CONSTRAINT (op, 'S') || GET_CODE (op) == REG); 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 in register class CLASS. We might be able to simplify this. */enum reg_classsecondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in){ /* 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 || (GET_CODE (in) == REG && REGNO (in) >= FIRST_PSEUDO_REGISTER) || (GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER)) && (mode == QImode || mode == HImode) && (class == ADDRESS_REGS || class == SP_REGS || class == SP_OR_ADDRESS_REGS)) { if (TARGET_AM33) return DATA_OR_EXTENDED_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 && class != SP_OR_EXTENDED_REGS && class != ADDRESS_OR_EXTENDED_REGS && class != SP_OR_ADDRESS_OR_EXTENDED_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)) { if (TARGET_AM33) return DATA_OR_EXTENDED_REGS; return DATA_REGS; } if (TARGET_AM33_2 && class == FP_REGS && GET_CODE (in) == MEM && ! OK_FOR_Q (in)) { if (TARGET_AM33) return DATA_OR_EXTENDED_REGS; return DATA_REGS; } /* Otherwise assume no secondary reloads are needed. */ return NO_REGS;}intinitial_offset (int from, int 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] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] || fp_regs_to_save () || frame_pointer_needed) return REG_SAVE_BYTES + 4 * fp_regs_to_save (); 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] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] || fp_regs_to_save () || frame_pointer_needed) return (get_frame_size () + REG_SAVE_BYTES + 4 * fp_regs_to_save () + (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 ();}/* Worker function for TARGET_RETURN_IN_MEMORY. */static boolmn10300_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED){ /* Return values > 8 bytes in length in memory. */ return int_size_in_bytes (type) > 8 || TYPE_MODE (type) == BLKmode;}/* Flush the argument registers to the stack for a stdarg function; return the new argument pointer. */static rtxmn10300_builtin_saveregs (void){ rtx offset, mem; 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); int set = get_varargs_alias_set (); if (argadj) offset = plus_constant (current_function_arg_offset_rtx, argadj); else offset = current_function_arg_offset_rtx; mem = gen_rtx_MEM (SImode, current_function_internal_arg_pointer); set_mem_alias_set (mem, set); emit_move_insn (mem, gen_rtx_REG (SImode, 0)); mem = gen_rtx_MEM (SImode, plus_constant (current_function_internal_arg_pointer, 4)); set_mem_alias_set (mem, set); emit_move_insn (mem, 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));}voidmn10300_va_start (tree valist, rtx nextarg){ nextarg = expand_builtin_saveregs (); std_expand_builtin_va_start (valist, nextarg);}/* Return true when a parameter should be passed by reference. */static boolmn10300_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, enum machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED){ unsigned HOST_WIDE_INT size; if (type) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); return size > 8;}/* 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 (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 bytes of registers to use for an argument passed partially in registers and partially in memory. */static intmn10300_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, bool 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -