📄 m68hc11.c
字号:
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 (cum, mode, type, named) 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 (mode, type) enum machine_mode mode; tree type;{ if (type != 0 && AGGREGATE_TYPE_P (type)) return upward; /* This is the default definition. */ return (!BYTES_BIG_ENDIAN ? upward : ((mode == BLKmode ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) ? downward : upward));}/* 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 (to, from, scratch) rtx to, from, 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 (){ 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 (out, size) 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 (){ 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; /* 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, GEN_INT (-1))); } /* 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 (){ 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]) { emit_move_after_reload (gen_rtx (REG, HImode, regno), stack_pop_word, scratch); } } /* de-allocate auto 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; for (i = 2; i <= size; i += 2) emit_move_after_reload (scratch, stack_pop_word, scratch); if (size & 1) emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (1))); } /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */ if (current_function_interrupt) { emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM), stack_pop_word, scratch); emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM), stack_pop_word, scratch); emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch); } /* Restore previous frame pointer. */ if (frame_pointer_needed) emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch); /* If the trap handler returns some value, copy the value in D, X onto the stack so that the rti will pop the return value correctly. */ else if (current_function_trap && return_size != 0) { rtx addr_reg = stack_pointer_rtx; if (!TARGET_M6812) { emit_move_after_reload (scratch, stack_pointer_rtx, 0); addr_reg = scratch; } emit_move_after_reload (gen_rtx (MEM, HImode, gen_rtx (PLUS, HImode, addr_reg, GEN_INT (1))), d_reg, 0); if (return_size > HARD_REG_SIZE) emit_move_after_reload (gen_rtx (MEM, HImode, gen_rtx (PLUS, HImode, addr_reg, GEN_INT (3))), ix_reg, 0); } emit_jump_insn (gen_return ());}/* Low and High part extraction for 68HC11. These routines are similar to gen_lowpart and gen_highpart but they have been fixed to work for constants and 68HC11 specific registers. */rtxm68hc11_gen_lowpart (mode, x) enum machine_mode mode; rtx x;{ /* We assume that the low part of an auto-inc mode is the same with the mode changed and that the caller split the larger mode in the correct order. */ if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) { return gen_rtx (MEM, mode, XEXP (x, 0)); } /* Note that a CONST_DOUBLE rtx could represent either an integer or a floating-point constant. A CONST_DOUBLE is used whenever the constant requires more than one word in order to be adequately represented. */ if (GET_CODE (x) == CONST_DOUBLE) { long l[2]; if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) { REAL_VALUE_TYPE r; if (GET_MODE (x) == SFmode) { REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_SINGLE (r, l[0]); } else { rtx first, second; split_double (x, &first, &second); return second; } if (mode == SImode) return GEN_INT (l[0]); return gen_int_mode (l[0], HImode); } else { l[0] = CONST_DOUBLE_LOW (x); } if (mode == SImode) return GEN_INT (l[0]); else if (mode == HImode && GET_MODE (x) == SFmode) return gen_int_mode (l[0], HImode); else abort (); } if (mode == QImode && D_REG_P (x)) return gen_rtx (REG, mode, HARD_B_REGNUM); /* gen_lowpart crashes when it is called with a SUBREG. */ if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0) { if (mode == SImode) return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4); else if (mode == HImode) return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2); else abort (); } x = gen_lowpart (mode, x); /* Return a different rtx to avoid to share it in several insns (when used by a split pattern). Sharing addresses within a MEM breaks the Z register replacement (and reloading). */ if (GET_CODE (x) == MEM) x = copy_rtx (x); return x;}rtxm68hc11_gen_highpart (mode, x) enum machine_mode mode; rtx x;{ /* We assume that the high part of an auto-inc mode is the same with the mode changed and that the caller split the larger mode in the correct order. */ if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) { return gen_rtx (MEM, mode, XEXP (x, 0)); } /* Note that a CONST_DOUBLE rtx could represent either an integer or a floating-point constant. A CONST_DOUBLE is used whenever the constant requires more than one word in order to be adequately represented. */ if (GET_CODE (x) == CONST_DOUBLE) { long l[2]; if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) { REAL_VALUE_TYPE r; if (GET_MODE (x) == SFmode) { REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_SINGLE (r, l[1]); } else { rtx first, second; split_double (x, &first, &second); return first; } if (mode == SImode) return GEN_INT (l[1]); return gen_int_mode ((l[1] >> 16), HImode); } else { l[1] = CONST_DOUBLE_HIGH (x); } if (mode == SImode) return GEN_INT (l[1]); else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) return gen_int_mode ((l[0] >> 16), HImode); else abort (); } if (GET_CODE (x) == CONST_INT) { HOST_WIDE_INT val = INTVAL (x); if (mode == QImode) { return gen_int_mode (val >> 8, QImode); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -