⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bfin.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
      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 + -