📄 bfin.c
字号:
if (lookup_attribute ("nesting", attrs)) n++; for (i = REG_P7 + 1; i < REG_CC; i++) if (all || regs_ever_live[i] || (!leaf_function_p () && call_used_regs[i])) n += i == REG_A0 || i == REG_A1 ? 2 : 1; } return n;}/* Return the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */HOST_WIDE_INTbfin_initial_elimination_offset (int from, int to){ HOST_WIDE_INT offset = 0; if (from == ARG_POINTER_REGNUM) offset = n_regs_saved_by_prologue () * 4; if (to == STACK_POINTER_REGNUM) { if (current_function_outgoing_args_size >= FIXED_STACK_AREA) offset += current_function_outgoing_args_size; else if (current_function_outgoing_args_size) offset += FIXED_STACK_AREA; offset += get_frame_size (); } return offset;}/* Emit code to load a constant CONSTANT into register REG; setting RTX_FRAME_RELATED_P on all insns we generate if RELATED is true. Make sure that the insns we generate need not be split. */static voidframe_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related){ rtx insn; rtx cst = GEN_INT (constant); if (constant >= -32768 && constant < 65536) insn = emit_move_insn (reg, cst); else { /* We don't call split_load_immediate here, since dwarf2out.c can get confused about some of the more clever sequences it can generate. */ insn = emit_insn (gen_movsi_high (reg, cst)); if (related) RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_movsi_low (reg, reg, cst)); } if (related) RTX_FRAME_RELATED_P (insn) = 1;}/* Generate efficient code to add a value to the frame pointer. We can use P1 as a scratch register. Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero. */static voidadd_to_sp (rtx spreg, HOST_WIDE_INT value, int frame){ if (value == 0) return; /* Choose whether to use a sequence using a temporary register, or a sequence with multiple adds. We can add a signed 7 bit value in one instruction. */ if (value > 120 || value < -120) { rtx tmpreg = gen_rtx_REG (SImode, REG_P1); rtx insn; if (frame) frame_related_constant_load (tmpreg, value, TRUE); else { insn = emit_move_insn (tmpreg, GEN_INT (value)); if (frame) RTX_FRAME_RELATED_P (insn) = 1; } insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg)); if (frame) RTX_FRAME_RELATED_P (insn) = 1; } else do { int size = value; rtx insn; if (size > 60) size = 60; else if (size < -60) /* We could use -62, but that would leave the stack unaligned, so it's no good. */ size = -60; insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size))); if (frame) RTX_FRAME_RELATED_P (insn) = 1; value -= size; } while (value != 0);}/* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant is too large, generate a sequence of insns that has the same effect. SPREG contains (reg:SI REG_SP). */static voidemit_link_insn (rtx spreg, HOST_WIDE_INT frame_size){ HOST_WIDE_INT link_size = frame_size; rtx insn; int i; if (link_size > 262140) link_size = 262140; /* Use a LINK insn with as big a constant as possible, then subtract any remaining size from the SP. */ insn = emit_insn (gen_link (GEN_INT (-8 - link_size))); RTX_FRAME_RELATED_P (insn) = 1; for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) { rtx set = XVECEXP (PATTERN (insn), 0, i); gcc_assert (GET_CODE (set) == SET); RTX_FRAME_RELATED_P (set) = 1; } frame_size -= link_size; if (frame_size > 0) { /* Must use a call-clobbered PREG that isn't the static chain. */ rtx tmpreg = gen_rtx_REG (Pmode, REG_P1); frame_related_constant_load (tmpreg, -frame_size, TRUE); insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg)); RTX_FRAME_RELATED_P (insn) = 1; }}/* Return the number of bytes we must reserve for outgoing arguments in the current function's stack frame. */static HOST_WIDE_INTarg_area_size (void){ if (current_function_outgoing_args_size) { if (current_function_outgoing_args_size >= FIXED_STACK_AREA) return current_function_outgoing_args_size; else return FIXED_STACK_AREA; } return 0;}/* Save RETS and FP, and allocate a stack frame. ALL is true if the function must save all its registers (true only for certain interrupt handlers). */static voiddo_link (rtx spreg, HOST_WIDE_INT frame_size, bool all){ frame_size += arg_area_size (); if (all || stack_frame_needed_p () || (must_save_fp_p () && ! current_function_is_leaf)) emit_link_insn (spreg, frame_size); else { if (! current_function_is_leaf) { rtx pat = gen_movsi (gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, spreg)), bfin_rets_rtx); rtx insn = emit_insn (pat); RTX_FRAME_RELATED_P (insn) = 1; } if (must_save_fp_p ()) { rtx pat = gen_movsi (gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, spreg)), gen_rtx_REG (Pmode, REG_FP)); rtx insn = emit_insn (pat); RTX_FRAME_RELATED_P (insn) = 1; } add_to_sp (spreg, -frame_size, 1); }}/* Like do_link, but used for epilogues to deallocate the stack frame. */static voiddo_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all){ frame_size += arg_area_size (); if (all || stack_frame_needed_p ()) emit_insn (gen_unlink ()); else { rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg)); add_to_sp (spreg, frame_size, 0); if (must_save_fp_p ()) { rtx fpreg = gen_rtx_REG (Pmode, REG_FP); emit_move_insn (fpreg, postinc); emit_insn (gen_rtx_USE (VOIDmode, fpreg)); } if (! current_function_is_leaf) { emit_move_insn (bfin_rets_rtx, postinc); emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx)); } }}/* Generate a prologue suitable for a function of kind FKIND. This is called for interrupt and exception handler prologues. SPREG contains (reg:SI REG_SP). */static voidexpand_interrupt_handler_prologue (rtx spreg, e_funkind fkind){ int i; HOST_WIDE_INT frame_size = get_frame_size (); rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg); rtx predec = gen_rtx_MEM (SImode, predec1); rtx insn; tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; tree kspisusp = lookup_attribute ("kspisusp", attrs); if (kspisusp) { insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP)); RTX_FRAME_RELATED_P (insn) = 1; } /* We need space on the stack in case we need to save the argument registers. */ if (fkind == EXCPT_HANDLER) { insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12))); RTX_FRAME_RELATED_P (insn) = 1; } insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT)); RTX_FRAME_RELATED_P (insn) = 1; /* If we're calling other functions, they won't save their call-clobbered registers, so we must save everything here. */ if (!current_function_is_leaf) all = true; expand_prologue_reg_save (spreg, all, true); for (i = REG_P7 + 1; i < REG_CC; i++) if (all || regs_ever_live[i] || (!leaf_function_p () && call_used_regs[i])) { if (i == REG_A0 || i == REG_A1) insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1), gen_rtx_REG (PDImode, i)); else insn = emit_move_insn (predec, gen_rtx_REG (SImode, i)); RTX_FRAME_RELATED_P (insn) = 1; } if (lookup_attribute ("nesting", attrs)) { rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX : fkind == NMI_HANDLER ? REG_RETN : REG_RETI)); insn = emit_move_insn (predec, srcreg); RTX_FRAME_RELATED_P (insn) = 1; } do_link (spreg, frame_size, all); if (fkind == EXCPT_HANDLER) { rtx r0reg = gen_rtx_REG (SImode, REG_R0); rtx r1reg = gen_rtx_REG (SImode, REG_R1); rtx r2reg = gen_rtx_REG (SImode, REG_R2); rtx insn; insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT)); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL_RTX); insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26))); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL_RTX); insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26))); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL_RTX); insn = emit_move_insn (r1reg, spreg); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL_RTX); insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP)); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL_RTX); insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8))); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL_RTX); }}/* Generate an epilogue suitable for a function of kind FKIND. This is called for interrupt and exception handler epilogues. SPREG contains (reg:SI REG_SP). */static voidexpand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind){ int i; rtx postinc1 = gen_rtx_POST_INC (SImode, spreg); rtx postinc = gen_rtx_MEM (SImode, postinc1); tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); bool all = lookup_attribute ("saveall", attrs) != NULL_TREE; /* A slightly crude technique to stop flow from trying to delete "dead" insns. */ MEM_VOLATILE_P (postinc) = 1; do_unlink (spreg, get_frame_size (), all); if (lookup_attribute ("nesting", attrs)) { rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX : fkind == NMI_HANDLER ? REG_RETN : REG_RETI)); emit_move_insn (srcreg, postinc); } /* If we're calling other functions, they won't save their call-clobbered registers, so we must save (and restore) everything here. */ if (!current_function_is_leaf) all = true; for (i = REG_CC - 1; i > REG_P7; i--) if (all || regs_ever_live[i] || (!leaf_function_p () && call_used_regs[i])) { if (i == REG_A0 || i == REG_A1) { rtx mem = gen_rtx_MEM (PDImode, postinc1); MEM_VOLATILE_P (mem) = 1; emit_move_insn (gen_rtx_REG (PDImode, i), mem); } else emit_move_insn (gen_rtx_REG (SImode, i), postinc); } expand_epilogue_reg_restore (spreg, all, true); emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc); /* Deallocate any space we left on the stack in case we needed to save the argument registers. */ if (fkind == EXCPT_HANDLER) emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12))); emit_jump_insn (gen_return_internal (GEN_INT (fkind)));}/* Used while emitting the prologue to generate code to load the correct value into the PIC register, which is passed in DEST. */static rtxbfin_load_pic_reg (rtx dest){ struct cgraph_local_info *i = NULL; rtx addr, insn; if (flag_unit_at_a_time) i = cgraph_local_info (current_function_decl); /* Functions local to the translation unit don't need to reload the pic reg, since the caller always passes a usable one. */ if (i && i->local) return pic_offset_table_rtx; if (bfin_lib_id_given) addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4); else addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_LIBRARY_OFFSET)); insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr))); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL); return dest;}/* Generate RTL for the prologue of the current function. */voidbfin_expand_prologue (void){ rtx insn; HOST_WIDE_INT frame_size = get_frame_size (); rtx spreg = gen_rtx_REG (Pmode, REG_SP); e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); rtx pic_reg_loaded = NULL_RTX; if (fkind != SUBROUTINE) { expand_interrupt_handler_prologue (spreg, fkind); return; } if (current_function_limit_stack) { HOST_WIDE_INT offset = bfin_initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM); rtx lim = stack_limit_rtx; if (GET_CODE (lim) == SYMBOL_REF) { rtx p2reg = gen_rtx_REG (Pmode, REG_P2); if (TARGET_ID_SHARED_LIBRARY) { rtx p1reg = gen_rtx_REG (Pmode, REG_P1); rtx val; pic_reg_loaded = bfin_load_pic_reg (p2reg); val = legitimize_pic_address (stack_limit_rtx, p1reg, pic_reg_loaded); emit_move_insn (p1reg, val); frame_related_constant_load (p2reg, offset, FALSE); emit_insn (gen_addsi3 (p2reg, p2reg, p1reg)); lim = p2reg; } else { rtx limit = plus_constant (stack_limit_rtx, offset); emit_move_insn (p2reg, limit); lim = p2reg; } } emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim)); emit_insn (gen_trapifcc ()); } expand_prologue_reg_save (spreg, 0, false); do_link (spreg, frame_size, false); if (TARGET_ID_SHARED_LIBRARY && (current_function_uses_pic_offset_table || !current_function_is_leaf)) bfin_load_pic_reg (pic_offset_table_rtx);}/* Generate RTL for the epilogue of the current function. NEED_RETURN is zero if this is for a sibcall. EH_RETURN is nonzero if we're expanding an eh_return pattern. */voidbfin_expand_epilogue (int need_return, int eh_return){ rtx spreg = gen_rtx_REG (Pmode, REG_SP); e_funkind fkind = funkind (TREE_TYPE (current_function_decl)); if (fkind != SUBROUTINE) { expand_interrupt_handler_epilogue (spreg, fkind); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -