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

📄 expr.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
      if (partial != 0)	xinner = change_address (xinner, BLKmode,				 plus_constant (XEXP (xinner, 0), used));/* If the partial register-part of the arg counts in its stack size,   skip the part of stack space corresponding to the registers.   Otherwise, start copying to the beginning of the stack space,   by setting SKIP to 0.  */#ifndef FIRST_PARM_CALLER_OFFSET      skip = 0;#else      skip = used;#endif#ifdef PUSH_ROUNDING      /* Do it with several push insns if that doesn't take lots of insns	 and if there is no difficulty with push insns that skip bytes	 on the stack for alignment purposes.  */      if (args_addr == 0	  && GET_CODE (size) == CONST_INT	  && args_addr == 0	  && skip == 0	  && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align)	      < MOVE_RATIO)	  && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))	move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner,			INTVAL (size) - used, align);      else#endif /* PUSH_ROUNDING */	{	  /* Otherwise make space on the stack and copy the data	     to the address of that space.  */	  /* Deduct words put into registers from the size we must copy.  */	  if (partial != 0)	    {	      if (GET_CODE (size) == CONST_INT)		size = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - used);	      else		size = expand_binop (GET_MODE (size), sub_optab, size,				     gen_rtx (CONST_INT, VOIDmode, used),				     0, 0, OPTAB_LIB_WIDEN);	    }	  /* Get the address of the stack space.  */	  if (! args_addr)	    {	      temp = push_block (size, extra);	      extra = 0;	    }	  else if (GET_CODE (args_so_far) == CONST_INT)	    temp = memory_address (BLKmode,				   plus_constant (args_addr,						  skip + INTVAL (args_so_far)));	  else	    temp = memory_address (BLKmode,				   plus_constant (gen_rtx (PLUS, Pmode,							   args_addr, args_so_far),						  skip));	  /* TEMP is the address of the block.  Copy the data there.  */	  if (GET_CODE (size) == CONST_INT	      && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)		  < MOVE_RATIO))	    {	      move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner,			      INTVAL (size), align);	      goto ret;	    }	  /* Try the most limited insn first, because there's no point	     including more than one in the machine description unless	     the more limited one has some advantage.  */#ifdef HAVE_movstrqi	  if (HAVE_movstrqi	      && GET_CODE (size) == CONST_INT	      && ((unsigned) INTVAL (size)		  < (1 << (GET_MODE_BITSIZE (QImode) - 1))))	    {	      emit_insn (gen_movstrqi (gen_rtx (MEM, BLKmode, temp),				       xinner, size,				       gen_rtx (CONST_INT, VOIDmode, align)));	      goto ret;	    }#endif#ifdef HAVE_movstrhi	  if (HAVE_movstrhi	      && GET_CODE (size) == CONST_INT	      && ((unsigned) INTVAL (size)		  < (1 << (GET_MODE_BITSIZE (HImode) - 1))))	    {	      emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp),				       xinner, size,				       gen_rtx (CONST_INT, VOIDmode, align)));	      goto ret;	    }#endif#ifdef HAVE_movstrsi	  if (HAVE_movstrsi)	    {	      emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp),				       xinner, size,				       gen_rtx (CONST_INT, VOIDmode, align)));	      goto ret;	    }#endif	  if (reg_mentioned_p (stack_pointer_rtx, temp))	    {	      /* Now that emit_library_call does force_operand		 before pushing anything, preadjustment does not work.  */	      temp = copy_to_reg (temp);#if 0	      /* Correct TEMP so it holds what will be a description of		 the address to copy to, valid after one arg is pushed.  */	      int xsize = GET_MODE_SIZE (Pmode);#ifdef PUSH_ROUNDING	      xsize = PUSH_ROUNDING (xsize);#endif	      xsize = ((xsize + PARM_BOUNDARY / BITS_PER_UNIT - 1)		       / (PARM_BOUNDARY / BITS_PER_UNIT)		       * (PARM_BOUNDARY / BITS_PER_UNIT));#ifdef TARGET_MEM_FUNCTIONS	      /* If we are calling bcopy, we push one arg before TEMP.		 If calling memcpy, we push two.  */	      xsize *= 2;#endif#ifdef STACK_GROWS_DOWNWARD	      temp = plus_constant (temp, xsize);#else	      temp = plus_constant (temp, -xsize);#endif /* not STACK_GROWS_DOWNWARD */#endif /* 0 */	    }	  /* Make inhibit_defer_pop nonzero around the library call	     to force it to pop the bcopy-arguments right away.  */	  NO_DEFER_POP;#ifdef TARGET_MEM_FUNCTIONS	  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,			     VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,			     size, Pmode);#else	  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,			     VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,			     size, Pmode);#endif	  OK_DEFER_POP;	}    }  else if (partial > 0)    {      /* Scalar partly in registers.  */      int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;      int i;      int not_stack;      /* # words of start of argument	 that we must make space for but need not store.  */      int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD);      int args_offset = INTVAL (args_so_far);      int skip;      /* If we make space by pushing it, we might as well push	 the real data.  Otherwise, we can leave OFFSET nonzero	 and leave the space uninitialized.  */      if (args_addr == 0)	offset = 0;      /* Now NOT_STACK gets the number of words that we don't need to	 allocate on the stack.  */      not_stack = partial - offset;/* If the partial register-part of the arg counts in its stack size,   skip the part of stack space corresponding to the registers.   Otherwise, start copying to the beginning of the stack space,   by setting SKIP to 0.  */#ifndef FIRST_PARM_CALLER_OFFSET      skip = 0;#else      skip = not_stack;#endif      if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx)	x = force_const_double_mem (x);      /* Loop over all the words allocated on the stack for this arg.  */      /* We can do it by words, because any scalar bigger than a word	 has a size a multiple of a word.  */#ifndef PUSH_ARGS_REVERSED      for (i = not_stack; i < size; i++)#else      for (i = size - 1; i >= not_stack; i--)#endif	if (i >= not_stack + offset)	  {	    rtx wd;	    rtx addr;	    /* Get the next word of the value in WD.  */	    if (GET_CODE (x) == MEM)	      {		rtx addr = memory_address (SImode,					   plus_constant (XEXP (x, 0),							  i * UNITS_PER_WORD));		/* Copy to a reg, since machine may lack		   memory-to-memory move insns.  */		wd = copy_to_reg (gen_rtx (MEM, SImode, addr));	      }	    else if (GET_CODE (x) == REG)	      wd = gen_rtx (SUBREG, SImode, x, i);	    else if (x == dconst0_rtx || x == const0_rtx)	      wd = const0_rtx;	    else	      abort ();	    emit_push_insn (wd,			    SImode, 0, align, 0, 0, 0, args_addr,			    gen_rtx (CONST_INT, VOIDmode,				     args_offset + (i - not_stack + skip) * UNITS_PER_WORD));	  }    }  else    {      rtx addr;#ifdef PUSH_ROUNDING      if (args_addr == 0)	addr = gen_push_operand ();      else#endif	if (GET_CODE (args_so_far) == CONST_INT)	  addr	    = memory_address (mode,			      plus_constant (args_addr, INTVAL (args_so_far)));      else	addr = memory_address (mode, gen_rtx (PLUS, Pmode, args_addr,					      args_so_far));      emit_move_insn (gen_rtx (MEM, mode, addr), x);    } ret:  /* If part should go in registers, copy that part     into the appropriate registers.  Do this now, at the end,     since mem-to-mem copies above may do function calls.  */  if (partial > 0)    move_block_to_reg (REGNO (reg), x, partial, align * BITS_PER_UNIT);  if (extra)    anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra));}/* Output a library call to function FUN (a SYMBOL_REF rtx)   (emitting the queue unless NO_QUEUE is nonzero),   for a value of mode OUTMODE,   with NARGS different arguments, passed as alternating rtx values   and machine_modes to convert them to.   The rtx values should have been passed through protect_from_queue already.  */voidemit_library_call (va_alist)     va_dcl{  register va_list p;  register int args_size = 0;  register int argnum;  enum machine_mode outmode;  int nargs;  rtx fun;  rtx orgfun;  int inc;  int count;  rtx *regvec;  rtx argblock = 0;  CUMULATIVE_ARGS args_so_far;  struct arg { rtx value; enum machine_mode mode; rtx reg; int partial; };  struct arg *argvec;  int old_inhibit_defer_pop = inhibit_defer_pop;  int stack_padding = 0;  int no_queue = 0;  rtx use_insns;  va_start (p);  orgfun = fun = va_arg (p, rtx);  no_queue = va_arg (p, int);  outmode = va_arg (p, enum machine_mode);  nargs = va_arg (p, int);  regvec = (rtx *) alloca (nargs * sizeof (rtx));  /* Copy all the libcall-arguments out of the varargs data     and into a vector ARGVEC.  */  argvec = (struct arg *) alloca (nargs * sizeof (struct arg));  INIT_CUMULATIVE_ARGS (args_so_far, (tree)0);  for (count = 0; count < nargs; count++)    {      rtx val = va_arg (p, rtx);      enum machine_mode mode = va_arg (p, enum machine_mode);      int arg_size;      argvec[count].value = val;      /* Convert the arg value to the mode the library wants.	 Also make sure it is a reasonable operand	 for a move or push insn.  */      /* ??? It is wrong to do it here; must do it earlier	 where we know the signedness of the arg.  */#ifdef GNULIB_NEEDS_DOUBLE      if (GNULIB_NEEDS_DOUBLE && mode == SFmode)	mode = DFmode;#endif      if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)	{	  val = gen_reg_rtx (mode);	  convert_move (val, argvec[count].value, 0);	}      else if (GET_CODE (val) != REG && GET_CODE (val) != MEM	       	       && ! ((CONSTANT_P (val) || GET_CODE (val) == CONST_DOUBLE)		     && LEGITIMATE_CONSTANT_P (val)))	val = force_operand (val, 0);      argvec[count].value = val;      argvec[count].mode = mode;      regvec[count] = FUNCTION_ARG (args_so_far, mode, (tree)0, 1);#ifdef FUNCTION_ARG_PARTIAL_NREGS      argvec[count].partial	= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, (tree)0, 1);#else      argvec[count].partial = 0;#endif      FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);    }  va_end (p);  /* If we have no actual push instructions, make space for all the args     right now.  */#ifndef PUSH_ROUNDING  for (count = 0; count < nargs; count++)    {      register enum machine_mode mode = argvec[count].mode;      register rtx reg = regvec[count];      register int partial = argvec[count].partial;      if (reg == 0 || partial != 0)	args_size += GET_MODE_SIZE (mode);      if (partial != 0)	args_size -= partial * GET_MODE_SIZE (SImode);    }  if (args_size != 0)    {#ifdef STACK_ARGS_ADJUST      struct args_size size;      size.constant = args_size;      size.var = 0;      STACK_ARGS_ADJUST (size);      args_size = size.constant;#endif      argblock	= push_block (round_push (gen_rtx (CONST_INT, VOIDmode, args_size)), 0);    }#endif /* no PUSH_ROUNDING */#ifdef PUSH_ARGS_REVERSED  inc = -1;  argnum = nargs - 1;#else  inc = 1;  argnum = 0;#endif  args_size = stack_padding;  for (count = 0; count < nargs; count++, argnum += inc)    {      register enum machine_mode mode = argvec[argnum].mode;      register rtx val = argvec[argnum].value;      rtx reg = regvec[argnum];      int partial = argvec[argnum].partial;      int arg_size;      if (reg != 0 && partial == 0)	emit_move_insn (reg, val);      else	emit_push_insn (val, mode, 0, 0, partial, reg, 0, argblock,			gen_rtx (CONST_INT, VOIDmode, args_size));      /* Compute size of stack space used by this argument.  */      if (reg == 0 || partial != 0)	arg_size = GET_MODE_SIZE (mode);      else	arg_size = 0;      if (partial != 0)	arg_size	  -= ((partial * UNITS_PER_WORD)	      / (PARM_BOUNDARY / BITS_PER_UNIT)	      * (PARM_BOUNDARY / BITS_PER_UNIT));      args_size += arg_size;      NO_DEFER_POP;    }  /* For version 1.37, try deleting this entirely.  */  if (! no_queue)    emit_queue ();  fun = prepare_call_address (fun, 0);  /* Any regs containing parms remain in use through the call.  */  start_sequence ();  for (count = 0; count < nargs; count++)    if (regvec[count] != 0)      emit_insn (gen_rtx (USE, VOIDmode, regvec[count]));  use_insns = gen_sequence ();  end_sequence ();#ifdef STACK_BOUNDARY  args_size = (args_size + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES;#endif  /* Don't allow popping to be deferred, since then     cse'ing of library calls could delete a call and leave the pop.  */  NO_DEFER_POP;  emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size,	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),	       outmode != VOIDmode ? hard_libcall_value (outmode) : 0,	       old_inhibit_defer_pop + 1, use_insns);  OK_DEFER_POP;}/* Expand an assignment that stores the value of FROM into TO.   If WANT_VALUE is nonzero, return an rtx for the value of TO.   (This may contain a QUEUED rtx.)   Otherwise, the returned value is not meaningful.   SUGGEST_REG is no longer actually used.   It used to mean, copy the value through a register   and return that register, if that is possible.   But now we do this if WANT_VALUE.   If the value stored is a constant, we return the constant.  */rtxexpand_assignment (to, from, want_value, suggest_reg)     tree to, from;     int want_value;     int suggest_reg;{  register rtx to_rtx = 0;

⌨️ 快捷键说明

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