📄 mn10300.c
字号:
/* Generate an instruction that pushes several registers onto the stack. Register K will be saved if bit K in MASK is set. The function does nothing if MASK is zero. To be compatible with the "movm" instruction, the lowest-numbered register must be stored in the lowest slot. If MASK is the set { R1,...,RN }, where R1...RN are ordered least first, the generated instruction will have the form: (parallel (set (reg:SI 9) (plus:SI (reg:SI 9) (const_int -N*4))) (set (mem:SI (plus:SI (reg:SI 9) (const_int -1*4))) (reg:SI RN)) ... (set (mem:SI (plus:SI (reg:SI 9) (const_int -N*4))) (reg:SI R1))) */voidmn10300_gen_multiple_store (mask) int mask;{ if (mask != 0) { int i; int count; rtx par; int pari; /* Count how many registers need to be saved. */ count = 0; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if ((mask & (1 << i)) != 0) count += 1; /* We need one PARALLEL element to update the stack pointer and an additional element for each register that is stored. */ par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1)); /* Create the instruction that updates the stack pointer. */ XVECEXP (par, 0, 0) = gen_rtx_SET (SImode, stack_pointer_rtx, gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (-count * 4))); /* Create each store. */ pari = 1; for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) if ((mask & (1 << i)) != 0) { rtx address = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (-pari * 4)); XVECEXP(par, 0, pari) = gen_rtx_SET (VOIDmode, gen_rtx_MEM (SImode, address), gen_rtx_REG (SImode, i)); pari += 1; } par = emit_insn (par); RTX_FRAME_RELATED_P (par) = 1; }}voidexpand_prologue (){ HOST_WIDE_INT size; /* SIZE includes the fixed stack space needed for function calls. */ size = get_frame_size () + current_function_outgoing_args_size; size += (current_function_outgoing_args_size ? 4 : 0); /* If we use any of the callee-saved registers, save them now. */ mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ()); /* Now put the frame pointer into the frame pointer register. */ if (frame_pointer_needed) emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); /* Allocate stack for this frame. */ if (size) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size)));}voidexpand_epilogue (){ HOST_WIDE_INT size; /* SIZE includes the fixed stack space needed for function calls. */ size = get_frame_size () + current_function_outgoing_args_size; size += (current_function_outgoing_args_size ? 4 : 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 circumstanes 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 (body, insn) 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); 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 (); }}/* 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 (op, mode) 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 = FIRST_PSEUDO_REGISTER; 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 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ 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 (class, mode, in) 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; } /* 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] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] || 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] || regs_ever_live[14] || regs_ever_live[15] || regs_ever_live[16] || regs_ever_live[17] || 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 (){ 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 (valist, nextarg) tree valist; rtx nextarg;{ nextarg = expand_builtin_saveregs (); std_expand_builtin_va_start (valist, nextarg);}rtxmn10300_va_arg (valist, type) tree valist, type;{ HOST_WIDE_INT align, rsize; tree t, ptr, pptr; /* Compute the rounded size of the type. */ align = PARM_BOUNDARY / BITS_PER_UNIT; rsize = (((int_size_in_bytes (type) + align - 1) / align) * align); t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist, build_int_2 ((rsize > 8 ? 4 : rsize), 0)); TREE_SIDE_EFFECTS (t) = 1; ptr = build_pointer_type (type); /* "Large" types are passed by reference. */ if (rsize > 8) { pptr = build_pointer_type (ptr); t = build1 (NOP_EXPR, pptr, t); TREE_SIDE_EFFECTS (t) = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -