📄 bfin.c
字号:
} 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); if (GET_CODE (set) != SET) abort (); 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); 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. */static voiddo_link (rtx spreg, HOST_WIDE_INT frame_size){ frame_size += arg_area_size (); if (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){ frame_size += arg_area_size (); if (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)); tree all = lookup_attribute ("saveall", attrs); 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; expand_prologue_reg_save (spreg, all != NULL_TREE); 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); 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)); tree all = lookup_attribute ("saveall", attrs); /* A slightly crude technique to stop flow from trying to delete "dead" insns. */ MEM_VOLATILE_P (postinc) = 1; do_unlink (spreg, get_frame_size ()); 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); } 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 != NULL_TREE); 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)));}/* 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)); if (fkind != SUBROUTINE) { expand_interrupt_handler_prologue (spreg, fkind); return; } expand_prologue_reg_save (spreg, 0); do_link (spreg, frame_size); if (TARGET_ID_SHARED_LIBRARY && (current_function_uses_pic_offset_table || !current_function_is_leaf)) { rtx addr; if (bfin_library_id_string) addr = plus_constant (pic_offset_table_rtx, atoi (bfin_library_id_string)); 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 (pic_offset_table_rtx, gen_rtx_MEM (Pmode, addr))); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL); }}/* 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; } do_unlink (spreg, get_frame_size ()); expand_epilogue_reg_restore (spreg, 0); /* Omit the return insn if this is for a sibcall. */ if (! need_return) return; if (eh_return) emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2))); emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));}/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */intbfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED, unsigned int new_reg){ /* Interrupt functions can only use registers that have already been saved by the prologue, even if they would normally be call-clobbered. */ if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE && !regs_ever_live[new_reg]) return 0; return 1;}/* Return the value of the return address for the frame COUNT steps up from the current frame, after the prologue. We punt for everything but the current frame by returning const0_rtx. */rtxbfin_return_addr_rtx (int count){ if (count != 0) return const0_rtx; return get_hard_reg_initial_val (Pmode, REG_RETS);}/* Try machine-dependent ways of modifying an illegitimate address X to be legitimate. If we find one, return the new, valid address, otherwise return NULL_RTX. OLDX is the address as it was before break_out_memory_refs was called. In some cases it is useful to look at this to decide what needs to be done. MODE is the mode of the memory reference. */rtxlegitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED){ return NULL_RTX;}/* This predicate is used to compute the length of a load/store insn. OP is a MEM rtx, we return nonzero if its addressing mode requires a 32 bit instruction. */inteffective_address_32bit_p (rtx op, enum machine_mode mode) { HOST_WIDE_INT offset; mode = GET_MODE (op); op = XEXP (op, 0); if (REG_P (op) || GET_CODE (op) == POST_INC || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC) return 0; if (GET_CODE (op) != PLUS) abort (); offset = INTVAL (XEXP (op, 1)); /* All byte loads use a 16 bit offset. */ if (GET_MODE_SIZE (mode) == 1) return 1; if (GET_MODE_SIZE (mode) == 4) { /* Frame pointer relative loads can use a negative offset, all others are restricted to a small positive one. */ if (XEXP (op, 0) == frame_pointer_rtx) return offset < -128 || offset > 60; return offset < 0 || offset > 60; } /* Must be HImode now. */ return offset < 0 || offset > 30;}/* Return cost of the memory address ADDR. All addressing modes are equally cheap on the Blackfin. */static intbfin_address_cost (rtx addr ATTRIBUTE_UNUSED){ return 1;}/* Subroutine of print_operand; used to print a memory reference X to FILE. */voidprint_address_operand (FILE *file, rtx x){ if (GET_CODE (x) == MEM) abort (); switch (GET_CODE (x)) { case PLUS: output_address (XEXP (x, 0)); fprintf (file, "+"); output_address (XEXP (x, 1)); break; case PRE_DEC: fprintf (file, "--"); output_address (XEXP (x, 0)); break; case POST_INC: output_address (XEXP (x, 0)); fprintf (file, "++"); break; case POST_DEC: output_address (XEXP (x, 0)); fprintf (file, "--"); break; default: print_operand (file, x, 0); }}/* Adding intp DImode support by Tony * -- Q: (low word) * -- R: (high word) */voidprint_operand (FILE *file, rtx x, char code){ enum machine_mode mode = GET_MODE (x); switch (code) { case 'j': switch (GET_CODE (x)) { case EQ: fprintf (file, "e"); break; case NE: fprintf (file, "ne"); break; case GT: fprintf (file, "g"); break; case LT: fprintf (file, "l"); break; case GE: fprintf (file, "ge"); break; case LE: fprintf (file, "le"); break; case GTU: fprintf (file, "g"); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -