📄 m68hc11.c
字号:
func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl)); if (lookup_attribute ("far", func_attr) != NULL_TREE) is_far = 1; else if (lookup_attribute ("near", func_attr) == NULL_TREE) is_far = TARGET_LONG_CALLS != 0; trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; if (trap_handler && is_far) { warning ("%<trap%> and %<far%> attributes are not compatible, ignoring %<far%>"); trap_handler = 0; } if (trap_handler) { if (trap_handler_symbol != 0) warning ("%<trap%> attribute is already used"); else trap_handler_symbol = XEXP (rtl, 0); } SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;}static unsigned intm68hc11_section_type_flags (tree decl, const char *name, int reloc){ unsigned int flags = default_section_type_flags (decl, name, reloc); if (strncmp (name, ".eeprom", 7) == 0) { flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE; } return flags;}intm68hc11_is_far_symbol (rtx sym){ if (GET_CODE (sym) == MEM) sym = XEXP (sym, 0); return SYMBOL_REF_FLAG (sym);}intm68hc11_is_trap_symbol (rtx sym){ if (GET_CODE (sym) == MEM) sym = XEXP (sym, 0); return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);}/* Argument support functions. *//* Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */intm68hc11_initial_elimination_offset (int from, int to){ int trap_handler; tree func_attr; int size; int regno; /* For a trap handler, we must take into account the registers which are pushed on the stack during the trap (except the PC). */ func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); current_function_interrupt = lookup_attribute ("interrupt", func_attr) != NULL_TREE; trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; if (lookup_attribute ("far", func_attr) != 0) current_function_far = 1; else if (lookup_attribute ("near", func_attr) != 0) current_function_far = 0; else current_function_far = (TARGET_LONG_CALLS != 0 && !current_function_interrupt && !trap_handler); if (trap_handler && from == ARG_POINTER_REGNUM) size = 7; /* For a function using 'call/rtc' we must take into account the page register which is pushed in the call. */ else if (current_function_far && from == ARG_POINTER_REGNUM) size = 1; else size = 0; if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) { /* 2 is for the saved frame. 1 is for the 'sts' correction when creating the frame. */ return get_frame_size () + 2 + m68hc11_sp_correction + size; } if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) { return m68hc11_sp_correction; } /* Push any 2 byte pseudo hard registers that we need to save. */ for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++) { if (regs_ever_live[regno] && !call_used_regs[regno]) { size += 2; } } if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM) { return get_frame_size () + size; } if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM) { return size; } return 0;}/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */voidm68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname){ tree ret_type; z_replacement_completed = 0; cum->words = 0; cum->nregs = 0; /* For a library call, we must find out the type of the return value. When the return value is bigger than 4 bytes, it is returned in memory. In that case, the first argument of the library call is a pointer to the memory location. Because the first argument is passed in register D, we have to identify this, so that the first function parameter is not passed in D either. */ if (fntype == 0) { const char *name; size_t len; if (libname == 0 || GET_CODE (libname) != SYMBOL_REF) return; /* If the library ends in 'di' or in 'df', we assume it's returning some DImode or some DFmode which are 64-bit wide. */ name = XSTR (libname, 0); len = strlen (name); if (len > 3 && ((name[len - 2] == 'd' && (name[len - 1] == 'f' || name[len - 1] == 'i')) || (name[len - 3] == 'd' && (name[len - 2] == 'i' || name[len - 2] == 'f')))) { /* We are in. Mark the first parameter register as already used. */ cum->words = 1; cum->nregs = 1; } return; } ret_type = TREE_TYPE (fntype); if (ret_type && aggregate_value_p (ret_type, fntype)) { cum->words = 1; cum->nregs = 1; }}/* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */voidm68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named ATTRIBUTE_UNUSED){ if (mode != BLKmode) { if (cum->words == 0 && GET_MODE_SIZE (mode) == 4) { cum->nregs = 2; cum->words = GET_MODE_SIZE (mode); } else { cum->words += GET_MODE_SIZE (mode); if (cum->words <= HARD_REG_SIZE) cum->nregs = 1; } } else { cum->words += int_size_in_bytes (type); } return;}/* Define where to put the arguments to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. MODE is the argument's machine mode. TYPE is the data type of the argument (as a tree). This is null for libcalls where that information may not be available. CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called. NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). */struct rtx_def *m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED){ if (cum->words != 0) { return NULL_RTX; } if (mode != BLKmode) { if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE) return gen_rtx_REG (mode, HARD_X_REGNUM); if (GET_MODE_SIZE (mode) > HARD_REG_SIZE) { return NULL_RTX; } return gen_rtx_REG (mode, HARD_D_REGNUM); } return NULL_RTX;}/* If defined, a C expression which determines whether, and in which direction, to pad out an argument with extra space. The value should be of type `enum direction': either `upward' to pad above the argument, `downward' to pad below, or `none' to inhibit padding. Structures are stored left shifted in their argument slot. */intm68hc11_function_arg_padding (enum machine_mode mode, tree type){ if (type != 0 && AGGREGATE_TYPE_P (type)) return upward; /* Fall back to the default. */ return DEFAULT_FUNCTION_ARG_PADDING (mode, type);}/* Function prologue and epilogue. *//* Emit a move after the reload pass has completed. This is used to emit the prologue and epilogue. */static voidemit_move_after_reload (rtx to, rtx from, rtx scratch){ rtx insn; if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from)) { insn = emit_move_insn (to, from); } else { emit_move_insn (scratch, from); insn = emit_move_insn (to, scratch); } /* Put a REG_INC note to tell the flow analysis that the instruction is necessary. */ if (IS_STACK_PUSH (to)) { REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (XEXP (to, 0), 0), REG_NOTES (insn)); } else if (IS_STACK_POP (from)) { REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (XEXP (from, 0), 0), REG_NOTES (insn)); } /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg to think that sp == _.frame and later replace a x = sp with x = _.frame. The problem is that we are lying to gcc and use `txs' for x = sp (which is not really true because txs is really x = sp + 1). */ else if (TARGET_M6811 && SP_REG_P (from)) { REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, from, REG_NOTES (insn)); }}intm68hc11_total_frame_size (void){ int size; int regno; size = get_frame_size (); if (current_function_interrupt) { size += 3 * HARD_REG_SIZE; } if (frame_pointer_needed) size += HARD_REG_SIZE; for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) if (regs_ever_live[regno] && !call_used_regs[regno]) size += HARD_REG_SIZE; return size;}static voidm68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED, HOST_WIDE_INT size ATTRIBUTE_UNUSED){ /* We catch the function epilogue generation to have a chance to clear the z_replacement_completed flag. */ z_replacement_completed = 0;}voidexpand_prologue (void){ tree func_attr; int size; int regno; rtx scratch; if (reload_completed != 1) abort (); size = get_frame_size (); create_regs_rtx (); /* Generate specific prologue for interrupt handlers. */ func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); current_function_interrupt = lookup_attribute ("interrupt", func_attr) != NULL_TREE; current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE; if (lookup_attribute ("far", func_attr) != NULL_TREE) current_function_far = 1; else if (lookup_attribute ("near", func_attr) != NULL_TREE) current_function_far = 0; else current_function_far = (TARGET_LONG_CALLS != 0 && !current_function_interrupt && !current_function_trap); /* Get the scratch register to build the frame and push registers. If the first argument is a 32-bit quantity, the D+X registers are used. Use Y to compute the frame. Otherwise, X is cheaper. For 68HC12, this scratch register is not used. */ if (current_function_args_info.nregs == 2) scratch = iy_reg; else scratch = ix_reg; /* Save current stack frame. */ if (frame_pointer_needed) emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch); /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy. Other soft registers in page0 need not to be saved because they will be restored by C functions. For a trap handler, we don't need to preserve these registers because this is a synchronous call. */ if (current_function_interrupt) { emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch); emit_move_after_reload (stack_push_word, gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch); emit_move_after_reload (stack_push_word, gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), scratch); } /* Allocate local variables. */ if (TARGET_M6812 && (size > 4 || size == 3)) { emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size))); } else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) { rtx insn; insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, gen_rtx_SET (VOIDmode, stack_pointer_rtx, gen_rtx_PLUS (HImode, stack_pointer_rtx, GEN_INT (-size))), gen_rtx_CLOBBER (VOIDmode, scratch))); emit_insn (insn); } else { int i; /* Allocate by pushing scratch values. */ for (i = 2; i <= size; i += 2) emit_move_after_reload (stack_push_word, ix_reg, 0); if (size & 1) emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx, constm1_rtx)); } /* Create the frame pointer. */ if (frame_pointer_needed) emit_move_after_reload (hard_frame_pointer_rtx, stack_pointer_rtx, scratch); /* Push any 2 byte pseudo hard registers that we need to save. */ for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) { if (regs_ever_live[regno] && !call_used_regs[regno]) { emit_move_after_reload (stack_push_word, gen_rtx_REG (HImode, regno), scratch); } }}voidexpand_epilogue (void){ int size; register int regno; int return_size; rtx scratch; if (reload_completed != 1) abort (); size = get_frame_size (); /* If we are returning a value in two registers, we have to preserve the X register and use the Y register to restore the stack and the saved registers. Otherwise, use X because it's faster (and smaller). */ if (current_function_return_rtx == 0) return_size = 0; else if (GET_CODE (current_function_return_rtx) == MEM) return_size = HARD_REG_SIZE; else return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx)); if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE) scratch = iy_reg; else scratch = ix_reg; /* Pop any 2 byte pseudo hard registers that we saved. */ for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--) { if (regs_ever_live[regno] && !call_used_regs[regno])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -