explow.c

来自「GCC编译器源代码」· C语言 代码 · 共 1,396 行 · 第 1/3 页

C
1,396
字号
	 created by the validize call also get moved to the right place.  */      if (sa != 0)	sa = validize_mem (sa);      emit_insn (fcn (sa, stack_pointer_rtx));      seq = gen_sequence ();      end_sequence ();      emit_insn_after (seq, after);    }  else    {      if (sa != 0)	sa = validize_mem (sa);      emit_insn (fcn (sa, stack_pointer_rtx));    }}/* Restore the stack pointer for the purpose in SAVE_LEVEL.  SA is the save   area made by emit_stack_save.  If it is zero, we have nothing to do.    Put any emitted insns after insn AFTER, if nonzero, otherwise at    current position.  */voidemit_stack_restore (save_level, sa, after)     enum save_level save_level;     rtx after;     rtx sa;{  /* The default is that we use a move insn.  */  rtx (*fcn) () = gen_move_insn;  /* See if this machine has anything special to do for this kind of save.  */  switch (save_level)    {#ifdef HAVE_restore_stack_block    case SAVE_BLOCK:      if (HAVE_restore_stack_block)	fcn = gen_restore_stack_block;      break;#endif#ifdef HAVE_restore_stack_function    case SAVE_FUNCTION:      if (HAVE_restore_stack_function)	fcn = gen_restore_stack_function;      break;#endif#ifdef HAVE_restore_stack_nonlocal    case SAVE_NONLOCAL:      if (HAVE_restore_stack_nonlocal)	fcn = gen_restore_stack_nonlocal;      break;#endif    default:      break;    }  if (sa != 0)    sa = validize_mem (sa);  if (after)    {      rtx seq;      start_sequence ();      emit_insn (fcn (stack_pointer_rtx, sa));      seq = gen_sequence ();      end_sequence ();      emit_insn_after (seq, after);    }  else    emit_insn (fcn (stack_pointer_rtx, sa));}/* Return an rtx representing the address of an area of memory dynamically   pushed on the stack.  This region of memory is always aligned to   a multiple of BIGGEST_ALIGNMENT.   Any required stack pointer alignment is preserved.   SIZE is an rtx representing the size of the area.   TARGET is a place in which the address can be placed.   KNOWN_ALIGN is the alignment (in bits) that we know SIZE has.  */rtxallocate_dynamic_stack_space (size, target, known_align)     rtx size;     rtx target;     int known_align;{  /* If we're asking for zero bytes, it doesn't matter what we point     to since we can't dereference it.  But return a reasonable     address anyway.  */  if (size == const0_rtx)    return virtual_stack_dynamic_rtx;  /* Otherwise, show we're calling alloca or equivalent.  */  current_function_calls_alloca = 1;  /* Ensure the size is in the proper mode.  */  if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)    size = convert_to_mode (Pmode, size, 1);  /* We will need to ensure that the address we return is aligned to     BIGGEST_ALIGNMENT.  If STACK_DYNAMIC_OFFSET is defined, we don't     always know its final value at this point in the compilation (it      might depend on the size of the outgoing parameter lists, for     example), so we must align the value to be returned in that case.     (Note that STACK_DYNAMIC_OFFSET will have a default non-zero value if     STACK_POINTER_OFFSET or ACCUMULATE_OUTGOING_ARGS are defined).     We must also do an alignment operation on the returned value if     the stack pointer alignment is less strict that BIGGEST_ALIGNMENT.     If we have to align, we must leave space in SIZE for the hole     that might result from the alignment operation.  */#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (STACK_BOUNDARY)#define MUST_ALIGN 1#else#define MUST_ALIGN (STACK_BOUNDARY < BIGGEST_ALIGNMENT)#endif  if (MUST_ALIGN)    {      if (GET_CODE (size) == CONST_INT)	size = GEN_INT (INTVAL (size)			+ (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1));      else	size = expand_binop (Pmode, add_optab, size,			     GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),			     NULL_RTX, 1, OPTAB_LIB_WIDEN);    }#ifdef SETJMP_VIA_SAVE_AREA  /* If setjmp restores regs from a save area in the stack frame,     avoid clobbering the reg save area.  Note that the offset of     virtual_incoming_args_rtx includes the preallocated stack args space.     It would be no problem to clobber that, but it's on the wrong side     of the old save area.  */  {    rtx dynamic_offset      = expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,		      stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);    size = expand_binop (Pmode, add_optab, size, dynamic_offset,			 NULL_RTX, 1, OPTAB_LIB_WIDEN);  }#endif /* SETJMP_VIA_SAVE_AREA */  /* Round the size to a multiple of the required stack alignment.     Since the stack if presumed to be rounded before this allocation,     this will maintain the required alignment.     If the stack grows downward, we could save an insn by subtracting     SIZE from the stack pointer and then aligning the stack pointer.     The problem with this is that the stack pointer may be unaligned     between the execution of the subtraction and alignment insns and     some machines do not allow this.  Even on those that do, some     signal handlers malfunction if a signal should occur between those     insns.  Since this is an extremely rare event, we have no reliable     way of knowing which systems have this problem.  So we avoid even     momentarily mis-aligning the stack.  */#ifdef STACK_BOUNDARY  /* If we added a variable amount to SIZE,     we can no longer assume it is aligned.  */#if !defined (SETJMP_VIA_SAVE_AREA)  if (MUST_ALIGN || known_align % STACK_BOUNDARY != 0)#endif    size = round_push (size);#endif  do_pending_stack_adjust ();  /* If needed, check that we have the required amount of stack.  Take into     account what has already been checked.  */  if (flag_stack_check && ! STACK_CHECK_BUILTIN)    probe_stack_range (STACK_CHECK_MAX_FRAME_SIZE + STACK_CHECK_PROTECT, size);  /* Don't use a TARGET that isn't a pseudo.  */  if (target == 0 || GET_CODE (target) != REG      || REGNO (target) < FIRST_PSEUDO_REGISTER)    target = gen_reg_rtx (Pmode);  mark_reg_pointer (target, known_align / BITS_PER_UNIT);  /* Perform the required allocation from the stack.  Some systems do     this differently than simply incrementing/decrementing from the     stack pointer, such as acquiring the space by calling malloc().  */#ifdef HAVE_allocate_stack  if (HAVE_allocate_stack)    {      enum machine_mode mode;      if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][0]	  && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][0])		(target, Pmode)))	target = copy_to_mode_reg (Pmode, target);      mode = insn_operand_mode[(int) CODE_FOR_allocate_stack][1];      size = convert_modes (mode, ptr_mode, size, 1);      if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][1]	  && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][1])		(size, mode)))	size = copy_to_mode_reg (mode, size);      emit_insn (gen_allocate_stack (target, size));    }  else#endif    {#ifndef STACK_GROWS_DOWNWARD      emit_move_insn (target, virtual_stack_dynamic_rtx);#endif      size = convert_modes (Pmode, ptr_mode, size, 1);      anti_adjust_stack (size);#ifdef STACK_GROWS_DOWNWARD  emit_move_insn (target, virtual_stack_dynamic_rtx);#endif    }  if (MUST_ALIGN)    {      /* CEIL_DIV_EXPR needs to worry about the addition overflowing,	 but we know it can't.  So add ourselves and then do	 TRUNC_DIV_EXPR.  */      target = expand_binop (Pmode, add_optab, target,			     GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),			     NULL_RTX, 1, OPTAB_LIB_WIDEN);      target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,			      GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),			      NULL_RTX, 1);      target = expand_mult (Pmode, target,			    GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),			    NULL_RTX, 1);    }    /* Some systems require a particular insn to refer to the stack     to make the pages exist.  */#ifdef HAVE_probe  if (HAVE_probe)    emit_insn (gen_probe ());#endif  /* Record the new stack level for nonlocal gotos.  */  if (nonlocal_goto_handler_slot != 0)    emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);  return target;}/* Emit one stack probe at ADDRESS, an address within the stack.  */static voidemit_stack_probe (address)     rtx address;{  rtx memref = gen_rtx (MEM, word_mode, address);  MEM_VOLATILE_P (memref) = 1;  if (STACK_CHECK_PROBE_LOAD)    emit_move_insn (gen_reg_rtx (word_mode), memref);  else    emit_move_insn (memref, const0_rtx);}/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.    FIRST is a constant and size is a Pmode RTX.  These are offsets from the   current stack pointer.  STACK_GROWS_DOWNWARD says whether to add or   subtract from the stack.  If SIZE is constant, this is done   with a fixed number of probes.  Otherwise, we must make a loop.  */#ifdef STACK_GROWS_DOWNWARD#define STACK_GROW_OP MINUS#else#define STACK_GROW_OP PLUS#endifvoidprobe_stack_range (first, size)     HOST_WIDE_INT first;     rtx size;{  /* First see if we have an insn to check the stack.  Use it if so.  */#ifdef HAVE_check_stack  if (HAVE_check_stack)    {      rtx last_addr = force_operand (gen_rtx (STACK_GROW_OP, Pmode,					      stack_pointer_rtx,					      plus_constant (size, first)),				     NULL_RTX);      if (insn_operand_predicate[(int) CODE_FOR_check_stack][0]	  && ! ((*insn_operand_predicate[(int) CODE_FOR_check_stack][0])		(last_address, Pmode)))	last_address = copy_to_mode_reg (Pmode, last_address);      emit_insn (gen_check_stack (last_address));      return;    }#endif  /* If we have to generate explicit probes, see if we have a constant     small number of them to generate.  If so, that's the easy case.  */  if (GET_CODE (size) == CONST_INT && INTVAL (size) < 10)    {      HOST_WIDE_INT offset;      /* Start probing at FIRST + N * STACK_CHECK_PROBE_INTERVAL	 for values of N from 1 until it exceeds LAST.  If only one	 probe is needed, this will not generate any code.  Then probe	 at LAST.  */      for (offset = first + STACK_CHECK_PROBE_INTERVAL;	   offset < INTVAL (size);	   offset = offset + STACK_CHECK_PROBE_INTERVAL)	emit_stack_probe (gen_rtx (STACK_GROW_OP, Pmode,				   stack_pointer_rtx, GEN_INT (offset)));      emit_stack_probe (gen_rtx (STACK_GROW_OP, Pmode, stack_pointer_rtx,				 plus_constant (size, first)));    }  /* In the variable case, do the same as above, but in a loop.  We emit loop     notes so that loop optimization can be done.  */  else    {      rtx test_addr	= force_operand (gen_rtx (STACK_GROW_OP, Pmode, stack_pointer_rtx,				  GEN_INT (first					   + STACK_CHECK_PROBE_INTERVAL)),			 NULL_RTX);      rtx last_addr	= force_operand (gen_rtx (STACK_GROW_OP, Pmode, stack_pointer_rtx,				  plus_constant (size, first)),			 NULL_RTX);      rtx incr = GEN_INT (STACK_CHECK_PROBE_INTERVAL);      rtx loop_lab = gen_label_rtx ();      rtx test_lab = gen_label_rtx ();      rtx end_lab = gen_label_rtx ();      rtx temp;      if (GET_CODE (test_addr) != REG	  || REGNO (test_addr) < FIRST_PSEUDO_REGISTER)	test_addr = force_reg (Pmode, test_addr);      emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);      emit_jump (test_lab);      emit_label (loop_lab);      emit_stack_probe (test_addr);      emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);#ifdef STACK_GROWS_DOWNWARD#define CMP_OPCODE GTU      temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr,			   1, OPTAB_WIDEN);#else#define CMP_OPCODE LTU      temp = expand_binop (Pmode, add_optab, test_addr, incr, test_addr,			   1, OPTAB_WIDEN);#endif      if (temp != test_addr)	abort ();      emit_label (test_lab);      emit_cmp_insn (test_addr, last_addr, CMP_OPCODE, NULL_RTX, Pmode, 1, 0);      emit_jump_insn ((*bcc_gen_fctn[(int) CMP_OPCODE]) (loop_lab));      emit_jump (end_lab);      emit_note (NULL_PTR, NOTE_INSN_LOOP_END);      emit_label (end_lab);      /* If will be doing stupid optimization, show test_addr is still live. */      if (obey_regdecls)	emit_insn (gen_rtx (USE, VOIDmode, test_addr));      emit_stack_probe (last_addr);    }}/* Return an rtx representing the register or memory location   in which a scalar value of data type VALTYPE   was returned by a function call to function FUNC.   FUNC is a FUNCTION_DECL node if the precise function is known,   otherwise 0.  */rtxhard_function_value (valtype, func)     tree valtype;     tree func;{  rtx val = FUNCTION_VALUE (valtype, func);  if (GET_CODE (val) == REG      && GET_MODE (val) == BLKmode)    {      int bytes = int_size_in_bytes (valtype);      enum machine_mode tmpmode;      for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);           tmpmode != MAX_MACHINE_MODE;           tmpmode = GET_MODE_WIDER_MODE (tmpmode))        {          /* Have we found a large enough mode?  */          if (GET_MODE_SIZE (tmpmode) >= bytes)            break;        }      /* No suitable mode found.  */      if (tmpmode == MAX_MACHINE_MODE)        abort ();      PUT_MODE (val, tmpmode);    }        return val;}/* Return an rtx representing the register or memory location   in which a scalar value of mode MODE was returned by a library call.  */rtxhard_libcall_value (mode)     enum machine_mode mode;{  return LIBCALL_VALUE (mode);}/* Look up the tree code for a given rtx code   to provide the arithmetic operation for REAL_ARITHMETIC.   The function returns an int because the caller may not know   what `enum tree_code' means.  */intrtx_to_tree_code (code)     enum rtx_code code;{  enum tree_code tcode;  switch (code)    {    case PLUS:      tcode = PLUS_EXPR;      break;    case MINUS:      tcode = MINUS_EXPR;      break;    case MULT:      tcode = MULT_EXPR;      break;    case DIV:      tcode = RDIV_EXPR;      break;    case SMIN:      tcode = MIN_EXPR;      break;    case SMAX:      tcode = MAX_EXPR;      break;    default:      tcode = LAST_AND_UNUSED_TREE_CODE;      break;    }  return ((int) tcode);}

⌨️ 快捷键说明

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