m68hc11.c
来自「gcc3.2.1源代码」· C语言 代码 · 共 2,530 行 · 第 1/5 页
C
2,530 行
build_int_2 (rounded_size, 0))); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); return addr;}/* 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; /* 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; /* 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); } /* Save current stack frame. */ if (frame_pointer_needed) emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, 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 (size > 8) { 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) 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 (size > 8) { 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))); } /* Restore previous frame pointer. */ if (frame_pointer_needed) emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch); /* 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); } /* 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 (trunc_int_for_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 (trunc_int_for_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 (trunc_int_for_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 (trunc_int_for_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 (trunc_int_for_mode (val >> 8, QImode)); } else if (mode == HImode) { return GEN_INT (trunc_int_for_mode (val >> 16, HImode)); } } if (mode == QImode && D_REG_P (x)) return gen_rtx (REG, mode, HARD_A_REGNUM); /* There is no way in GCC to represent the upper part of a word register. To obtain the 8-bit upper part of a soft register, we change the reg into a mem rtx. This is possible because they are physically located in memory. There is no offset because we are big-endian. */ if (mode == QImode && S_REG_P (x)) { int pos; /* Avoid the '*' for direct addressing mode when this addressing mode is disabled. */ pos = TARGET_NO_DIRECT_MODE ? 1 : 0; return gen_rtx (MEM, QImode, gen_rtx (SYMBOL_REF, Pmode, ®_names[REGNO (x)][pos])); } /* gen_highpart crashes when it is called with a SUBREG. */ if (GET_CODE (x) == SUBREG) { return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1)); } if (GET_CODE (x) == REG) { if (REGNO (x) < FIRST_PSEUDO_REGISTER) return gen_rtx (REG, mode, REGNO (x)); else return gen_rtx_SUBREG (mode, x, 0); } if (GET_CODE (x) == MEM) { x = change_address (x, mode, 0); /* 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?