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

📄 ia64.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
     rtx in;     int force;{  if (GET_CODE (in) == SUBREG      && GET_MODE (SUBREG_REG (in)) == TImode      && GET_CODE (SUBREG_REG (in)) == REG)    {      rtx mem = gen_mem_addressof (SUBREG_REG (in), NULL_TREE, true);      return gen_rtx_MEM (TFmode, copy_to_reg (XEXP (mem, 0)));    }  else if (force && GET_CODE (in) == REG)    {      rtx mem = gen_mem_addressof (in, NULL_TREE, true);      return gen_rtx_MEM (TFmode, copy_to_reg (XEXP (mem, 0)));    }  else if (GET_CODE (in) == MEM	   && GET_CODE (XEXP (in, 0)) == ADDRESSOF)    return change_address (in, TFmode, copy_to_reg (XEXP (in, 0)));  else    return in;}/* Emit comparison instruction if necessary, returning the expression   that holds the compare result in the proper mode.  */rtxia64_expand_compare (code, mode)     enum rtx_code code;     enum machine_mode mode;{  rtx op0 = ia64_compare_op0, op1 = ia64_compare_op1;  rtx cmp;  /* If we have a BImode input, then we already have a compare result, and     do not need to emit another comparison.  */  if (GET_MODE (op0) == BImode)    {      if ((code == NE || code == EQ) && op1 == const0_rtx)	cmp = op0;      else	abort ();    }  else    {      cmp = gen_reg_rtx (BImode);      emit_insn (gen_rtx_SET (VOIDmode, cmp,			      gen_rtx_fmt_ee (code, BImode, op0, op1)));      code = NE;    }  return gen_rtx_fmt_ee (code, mode, cmp, const0_rtx);}/* Emit the appropriate sequence for a call.  */voidia64_expand_call (retval, addr, nextarg, sibcall_p)     rtx retval;     rtx addr;     rtx nextarg ATTRIBUTE_UNUSED;     int sibcall_p;{  rtx insn, b0;  addr = XEXP (addr, 0);  addr = convert_memory_address (DImode, addr);  b0 = gen_rtx_REG (DImode, R_BR (0));  /* ??? Should do this for functions known to bind local too.  */  if (TARGET_NO_PIC || TARGET_AUTO_PIC)    {      if (sibcall_p)	insn = gen_sibcall_nogp (addr);      else if (! retval)	insn = gen_call_nogp (addr, b0);      else	insn = gen_call_value_nogp (retval, addr, b0);      insn = emit_call_insn (insn);    }  else    {      if (sibcall_p)	insn = gen_sibcall_gp (addr);      else if (! retval)	insn = gen_call_gp (addr, b0);      else	insn = gen_call_value_gp (retval, addr, b0);      insn = emit_call_insn (insn);      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);    }  if (sibcall_p)    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), b0);}voidia64_reload_gp (){  rtx tmp;  if (current_frame_info.reg_save_gp)    tmp = gen_rtx_REG (DImode, current_frame_info.reg_save_gp);  else    {      HOST_WIDE_INT offset;      offset = (current_frame_info.spill_cfa_off	        + current_frame_info.spill_size);      if (frame_pointer_needed)        {          tmp = hard_frame_pointer_rtx;          offset = -offset;        }      else        {          tmp = stack_pointer_rtx;          offset = current_frame_info.total_size - offset;        }      if (CONST_OK_FOR_I (offset))        emit_insn (gen_adddi3 (pic_offset_table_rtx,			       tmp, GEN_INT (offset)));      else        {          emit_move_insn (pic_offset_table_rtx, GEN_INT (offset));          emit_insn (gen_adddi3 (pic_offset_table_rtx,			         pic_offset_table_rtx, tmp));        }      tmp = gen_rtx_MEM (DImode, pic_offset_table_rtx);    }  emit_move_insn (pic_offset_table_rtx, tmp);}voidia64_split_call (retval, addr, retaddr, scratch_r, scratch_b,		 noreturn_p, sibcall_p)     rtx retval, addr, retaddr, scratch_r, scratch_b;     int noreturn_p, sibcall_p;{  rtx insn;  bool is_desc = false;  /* If we find we're calling through a register, then we're actually     calling through a descriptor, so load up the values.  */  if (REG_P (addr) && GR_REGNO_P (REGNO (addr)))    {      rtx tmp;      bool addr_dead_p;      /* ??? We are currently constrained to *not* use peep2, because	 we can legitimiately change the global lifetime of the GP	 (in the form of killing where previously live).  This is 	 because a call through a descriptor doesn't use the previous	 value of the GP, while a direct call does, and we do not	 commit to either form until the split here.	 That said, this means that we lack precise life info for	 whether ADDR is dead after this call.  This is not terribly	 important, since we can fix things up essentially for free	 with the POST_DEC below, but it's nice to not use it when we	 can immediately tell it's not necessary.  */      addr_dead_p = ((noreturn_p || sibcall_p		      || TEST_HARD_REG_BIT (regs_invalidated_by_call,					    REGNO (addr)))		     && !FUNCTION_ARG_REGNO_P (REGNO (addr)));      /* Load the code address into scratch_b.  */      tmp = gen_rtx_POST_INC (Pmode, addr);      tmp = gen_rtx_MEM (Pmode, tmp);      emit_move_insn (scratch_r, tmp);      emit_move_insn (scratch_b, scratch_r);      /* Load the GP address.  If ADDR is not dead here, then we must	 revert the change made above via the POST_INCREMENT.  */      if (!addr_dead_p)	tmp = gen_rtx_POST_DEC (Pmode, addr);      else	tmp = addr;      tmp = gen_rtx_MEM (Pmode, tmp);      emit_move_insn (pic_offset_table_rtx, tmp);      is_desc = true;      addr = scratch_b;    }  if (sibcall_p)    insn = gen_sibcall_nogp (addr);  else if (retval)    insn = gen_call_value_nogp (retval, addr, retaddr);  else    insn = gen_call_nogp (addr, retaddr);  emit_call_insn (insn);  if ((!TARGET_CONST_GP || is_desc) && !noreturn_p && !sibcall_p)    ia64_reload_gp ();}/* Begin the assembly file.  */voidemit_safe_across_calls (f)     FILE *f;{  unsigned int rs, re;  int out_state;  rs = 1;  out_state = 0;  while (1)    {      while (rs < 64 && call_used_regs[PR_REG (rs)])	rs++;      if (rs >= 64)	break;      for (re = rs + 1; re < 64 && ! call_used_regs[PR_REG (re)]; re++)	continue;      if (out_state == 0)	{	  fputs ("\t.pred.safe_across_calls ", f);	  out_state = 1;	}      else	fputc (',', f);      if (re == rs + 1)	fprintf (f, "p%u", rs);      else	fprintf (f, "p%u-p%u", rs, re - 1);      rs = re + 1;    }  if (out_state)    fputc ('\n', f);}/* Helper function for ia64_compute_frame_size: find an appropriate general   register to spill some special register to.  SPECIAL_SPILL_MASK contains   bits in GR0 to GR31 that have already been allocated by this routine.   TRY_LOCALS is true if we should attempt to locate a local regnum.  */static intfind_gr_spill (try_locals)     int try_locals;{  int regno;  /* If this is a leaf function, first try an otherwise unused     call-clobbered register.  */  if (current_function_is_leaf)    {      for (regno = GR_REG (1); regno <= GR_REG (31); regno++)	if (! regs_ever_live[regno]	    && call_used_regs[regno]	    && ! fixed_regs[regno]	    && ! global_regs[regno]	    && ((current_frame_info.gr_used_mask >> regno) & 1) == 0)	  {	    current_frame_info.gr_used_mask |= 1 << regno;	    return regno;	  }    }  if (try_locals)    {      regno = current_frame_info.n_local_regs;      /* If there is a frame pointer, then we can't use loc79, because	 that is HARD_FRAME_POINTER_REGNUM.  In particular, see the	 reg_name switching code in ia64_expand_prologue.  */      if (regno < (80 - frame_pointer_needed))	{	  current_frame_info.n_local_regs = regno + 1;	  return LOC_REG (0) + regno;	}    }  /* Failed to find a general register to spill to.  Must use stack.  */  return 0;}/* In order to make for nice schedules, we try to allocate every temporary   to a different register.  We must of course stay away from call-saved,   fixed, and global registers.  We must also stay away from registers   allocated in current_frame_info.gr_used_mask, since those include regs   used all through the prologue.   Any register allocated here must be used immediately.  The idea is to   aid scheduling, not to solve data flow problems.  */static int last_scratch_gr_reg;static intnext_scratch_gr_reg (){  int i, regno;  for (i = 0; i < 32; ++i)    {      regno = (last_scratch_gr_reg + i + 1) & 31;      if (call_used_regs[regno]	  && ! fixed_regs[regno]	  && ! global_regs[regno]	  && ((current_frame_info.gr_used_mask >> regno) & 1) == 0)	{	  last_scratch_gr_reg = regno;	  return regno;	}    }  /* There must be _something_ available.  */  abort ();}/* Helper function for ia64_compute_frame_size, called through   diddle_return_value.  Mark REG in current_frame_info.gr_used_mask.  */static voidmark_reg_gr_used_mask (reg, data)     rtx reg;     void *data ATTRIBUTE_UNUSED;{  unsigned int regno = REGNO (reg);  if (regno < 32)    {      unsigned int i, n = HARD_REGNO_NREGS (regno, GET_MODE (reg));      for (i = 0; i < n; ++i)	current_frame_info.gr_used_mask |= 1 << (regno + i);    }}/* Returns the number of bytes offset between the frame pointer and the stack   pointer for the current function.  SIZE is the number of bytes of space   needed for local variables.  */static voidia64_compute_frame_size (size)     HOST_WIDE_INT size;{  HOST_WIDE_INT total_size;  HOST_WIDE_INT spill_size = 0;  HOST_WIDE_INT extra_spill_size = 0;  HOST_WIDE_INT pretend_args_size;  HARD_REG_SET mask;  int n_spilled = 0;  int spilled_gr_p = 0;  int spilled_fr_p = 0;  unsigned int regno;  int i;  if (current_frame_info.initialized)    return;  memset (&current_frame_info, 0, sizeof current_frame_info);  CLEAR_HARD_REG_SET (mask);  /* Don't allocate scratches to the return register.  */  diddle_return_value (mark_reg_gr_used_mask, NULL);  /* Don't allocate scratches to the EH scratch registers.  */  if (cfun->machine->ia64_eh_epilogue_sp)    mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_sp, NULL);  if (cfun->machine->ia64_eh_epilogue_bsp)    mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_bsp, NULL);  /* Find the size of the register stack frame.  We have only 80 local     registers, because we reserve 8 for the inputs and 8 for the     outputs.  */  /* Skip HARD_FRAME_POINTER_REGNUM (loc79) when frame_pointer_needed,     since we'll be adjusting that down later.  */  regno = LOC_REG (78) + ! frame_pointer_needed;  for (; regno >= LOC_REG (0); regno--)    if (regs_ever_live[regno])      break;  current_frame_info.n_local_regs = regno - LOC_REG (0) + 1;  /* For functions marked with the syscall_linkage attribute, we must mark     all eight input registers as in use, so that locals aren't visible to     the caller.  */  if (cfun->machine->n_varargs > 0      || lookup_attribute ("syscall_linkage",			   TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))    current_frame_info.n_input_regs = 8;  else    {      for (regno = IN_REG (7); regno >= IN_REG (0); regno--)	if (regs_ever_live[regno])	  break;      current_frame_info.n_input_regs = regno - IN_REG (0) + 1;    }  for (regno = OUT_REG (7); regno >= OUT_REG (0); regno--)    if (regs_ever_live[regno])      break;  i = regno - OUT_REG (0) + 1;  /* When -p profiling, we need one output register for the mcount argument.     Likwise for -a profiling for the bb_init_func argument.  For -ax     profiling, we need two output registers for the two bb_init_trace_func     arguments.  */  if (current_function_profile)    i = MAX (i, 1);  current_frame_info.n_output_regs = i;  /* ??? No rotating register support yet.  */  current_frame_info.n_rotate_regs = 0;  /* Discover which registers need spilling, and how much room that     will take.  Begin with floating point and general registers,      which will always wind up on the stack.  */  for (regno = FR_REG (2); regno <= FR_REG (127); regno++)    if (regs_ever_live[regno] && ! call_used_regs[regno])      {	SET_HARD_REG_BIT (mask, regno);	spill_size += 16;	n_spilled += 1;	spilled_fr_p = 1;      }  for (regno = GR_REG (1); regno <= GR_REG (31); regno++)    if (regs_ever_live[regno] && ! call_used_regs[regno])      {	SET_HARD_REG_BIT (mask, regno);	spill_size += 8;	n_spilled += 1;	spilled_gr_p = 1;      }  for (regno = BR_REG (1); regno <= BR_REG (7); regno++)    if (regs_ever_live[regno] && ! call_used_regs[regno])      {	SET_HARD_REG_BIT (mask, regno);	spill_size += 8;	n_spilled += 1;      }  /* Now come all special registers that might get saved in other     general registers.  */    if (frame_pointer_needed)    {      current_frame_info.reg_fp = find_gr_spill (1);      /* If we did not get a register, then we take LOC79.  This is guaranteed	 to be free, even if regs_ever_live is already set, because this is	 HARD_FRAME_POINTER_REGNUM.  This requires incrementing n_local_regs,	 as we don't count loc79 above.  */      if (current_frame_info.reg_fp == 0)	{	  current_frame_info.reg_fp = LOC_REG (79);	  current_frame_info.n_local_regs++;	}    }  if (! current_function_is_leaf)    {      /* Emit a save of BR0 if we call other functions.  Do this even

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -