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

📄 function.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
  p->cleanup_label = cleanup_label;  p->return_label = return_label;  p->save_expr_regs = save_expr_regs;  p->stack_slot_list = stack_slot_list;  p->parm_birth_insn = parm_birth_insn;  p->frame_offset = frame_offset;  p->tail_recursion_label = tail_recursion_label;  p->tail_recursion_reentry = tail_recursion_reentry;  p->arg_pointer_save_area = arg_pointer_save_area;  p->rtl_expr_chain = rtl_expr_chain;  p->last_parm_insn = last_parm_insn;  p->context_display = context_display;  p->trampoline_list = trampoline_list;  p->function_call_count = function_call_count;  p->temp_slots = temp_slots;  p->temp_slot_level = temp_slot_level;  p->fixup_var_refs_queue = 0;  p->epilogue_delay_list = current_function_epilogue_delay_list;  save_tree_status (p);  save_storage_status (p);  save_emit_status (p);  init_emit ();  save_expr_status (p);  save_stmt_status (p);  save_varasm_status (p);}/* Restore the last saved context, at the end of a nested function.   This function is called from language-specific code.  */voidpop_function_context (){  struct function *p = outer_function_chain;  outer_function_chain = p->next;  current_function_name = p->name;  current_function_decl = p->decl;  current_function_pops_args = p->pops_args;  current_function_returns_struct = p->returns_struct;  current_function_returns_pcc_struct = p->returns_pcc_struct;  current_function_needs_context = p->needs_context;  current_function_calls_setjmp = p->calls_setjmp;  current_function_calls_longjmp = p->calls_longjmp;  current_function_calls_alloca = p->calls_alloca;  current_function_has_nonlocal_label = p->has_nonlocal_label;  current_function_contains_functions = 1;  current_function_args_size = p->args_size;  current_function_pretend_args_size = p->pretend_args_size;  current_function_arg_offset_rtx = p->arg_offset_rtx;  current_function_uses_const_pool = p->uses_const_pool;  current_function_uses_pic_offset_table = p->uses_pic_offset_table;  current_function_internal_arg_pointer = p->internal_arg_pointer;  max_parm_reg = p->max_parm_reg;  parm_reg_stack_loc = p->parm_reg_stack_loc;  current_function_outgoing_args_size = p->outgoing_args_size;  current_function_return_rtx = p->return_rtx;  nonlocal_goto_handler_slot = p->nonlocal_goto_handler_slot;  nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;  nonlocal_labels = p->nonlocal_labels;  cleanup_label = p->cleanup_label;  return_label = p->return_label;  save_expr_regs = p->save_expr_regs;  stack_slot_list = p->stack_slot_list;  parm_birth_insn = p->parm_birth_insn;  frame_offset = p->frame_offset;  tail_recursion_label = p->tail_recursion_label;  tail_recursion_reentry = p->tail_recursion_reentry;  arg_pointer_save_area = p->arg_pointer_save_area;  rtl_expr_chain = p->rtl_expr_chain;  last_parm_insn = p->last_parm_insn;  context_display = p->context_display;  trampoline_list = p->trampoline_list;  function_call_count = p->function_call_count;  temp_slots = p->temp_slots;  temp_slot_level = p->temp_slot_level;  current_function_epilogue_delay_list = p->epilogue_delay_list;  restore_tree_status (p);  restore_storage_status (p);  restore_expr_status (p);  restore_emit_status (p);  restore_stmt_status (p);  restore_varasm_status (p);  /* Finish doing put_var_into_stack for any of our variables     which became addressable during the nested function.  */  {    struct var_refs_queue *queue = p->fixup_var_refs_queue;    for (; queue; queue = queue->next)      fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);  }  free (p);  /* Reset variables that have known state during rtx generation.  */  rtx_equal_function_value_matters = 1;  virtuals_instantiated = 0;}/* Allocate fixed slots in the stack frame of the current function.  *//* Return size needed for stack frame based on slots so far allocated.   This size counts from zero.  It is not rounded to STACK_BOUNDARY;   the caller may have to do that.  */intget_frame_size (){#ifdef FRAME_GROWS_DOWNWARD  return -frame_offset;#else  return frame_offset;#endif}/* Allocate a stack slot of SIZE bytes and return a MEM rtx for it   with machine mode MODE.      ALIGN controls the amount of alignment for the address of the slot:   0 means according to MODE,   -1 means use BIGGEST_ALIGNMENT and round size to multiple of that,   positive specifies alignment boundary in bits.   We do not round to stack_boundary here.  */rtxassign_stack_local (mode, size, align)     enum machine_mode mode;     int size;     int align;{  register rtx x, addr;  int bigend_correction = 0;  int alignment;  if (align == 0)    {      alignment = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;      if (mode == BLKmode)	alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;    }  else if (align == -1)    {      alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;      size = CEIL_ROUND (size, alignment);    }  else    alignment = align / BITS_PER_UNIT;  /* Round frame offset to that alignment.     We must be careful here, since FRAME_OFFSET might be negative and     division with a negative dividend isn't as well defined as we might     like.  So we instead assume that ALIGNMENT is a power of two and     use logical operations which are unambiguous.  */#ifdef FRAME_GROWS_DOWNWARD  frame_offset = FLOOR_ROUND (frame_offset, alignment);#else  frame_offset = CEIL_ROUND (frame_offset, alignment);#endif  /* On a big-endian machine, if we are allocating more space than we will use,     use the least significant bytes of those that are allocated.  */#if BYTES_BIG_ENDIAN  if (mode != BLKmode)    bigend_correction = size - GET_MODE_SIZE (mode);#endif#ifdef FRAME_GROWS_DOWNWARD  frame_offset -= size;#endif  /* If we have already instantiated virtual registers, return the actual     address relative to the frame pointer.  */  if (virtuals_instantiated)    addr = plus_constant (frame_pointer_rtx,			  (frame_offset + bigend_correction			   + STARTING_FRAME_OFFSET));  else    addr = plus_constant (virtual_stack_vars_rtx,			  frame_offset + bigend_correction);#ifndef FRAME_GROWS_DOWNWARD  frame_offset += size;#endif  x = gen_rtx (MEM, mode, addr);  stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, x, stack_slot_list);  return x;}/* Assign a stack slot in a containing function.   First three arguments are same as in preceding function.   The last argument specifies the function to allocate in.  */rtxassign_outer_stack_local (mode, size, align, function)     enum machine_mode mode;     int size;     int align;     struct function *function;{  register rtx x, addr;  int bigend_correction = 0;  int alignment;  /* Allocate in the memory associated with the function in whose frame     we are assigning.  */  push_obstacks (function->function_obstack,		 function->function_maybepermanent_obstack);  if (align == 0)    {      alignment = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;      if (mode == BLKmode)	alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;    }  else if (align == -1)    {      alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;      size = CEIL_ROUND (size, alignment);    }  else    alignment = align / BITS_PER_UNIT;  /* Round frame offset to that alignment.  */#ifdef FRAME_GROWS_DOWNWARD  function->frame_offset = FLOOR_ROUND (function->frame_offset, alignment);#else  function->frame_offset = CEIL_ROUND (function->frame_offset, alignment);#endif  /* On a big-endian machine, if we are allocating more space than we will use,     use the least significant bytes of those that are allocated.  */#if BYTES_BIG_ENDIAN  if (mode != BLKmode)    bigend_correction = size - GET_MODE_SIZE (mode);#endif#ifdef FRAME_GROWS_DOWNWARD  function->frame_offset -= size;#endif  addr = plus_constant (virtual_stack_vars_rtx,			function->frame_offset + bigend_correction);#ifndef FRAME_GROWS_DOWNWARD  function->frame_offset += size;#endif  x = gen_rtx (MEM, mode, addr);  function->stack_slot_list    = gen_rtx (EXPR_LIST, VOIDmode, x, function->stack_slot_list);  pop_obstacks ();  return x;}/* Allocate a temporary stack slot and record it for possible later   reuse.   MODE is the machine mode to be given to the returned rtx.   SIZE is the size in units of the space required.  We do no rounding here   since assign_stack_local will do any required rounding.   KEEP is non-zero if this slot is to be retained after a call to   free_temp_slots.  Automatic variables for a block are allocated with this   flag.  */rtxassign_stack_temp (mode, size, keep)     enum machine_mode mode;     int size;     int keep;{  struct temp_slot *p, *best_p = 0;  /* First try to find an available, already-allocated temporary that is the     exact size we require.  */  for (p = temp_slots; p; p = p->next)    if (p->size == size && GET_MODE (p->slot) == mode && ! p->in_use)      break;  /* If we didn't find, one, try one that is larger than what we want.  We     find the smallest such.  */  if (p == 0)    for (p = temp_slots; p; p = p->next)      if (p->size > size && GET_MODE (p->slot) == mode && ! p->in_use	  && (best_p == 0 || best_p->size > p->size))	best_p = p;  /* Make our best, if any, the one to use.  */  if (best_p)    p = best_p;  /* If we still didn't find one, make a new temporary.  */  if (p == 0)    {      p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));      p->size = size;      /* If the temp slot mode doesn't indicate the alignment,	 use the largest possible, so no one will be disappointed.  */      p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0);       p->next = temp_slots;      temp_slots = p;    }  p->in_use = 1;  p->level = temp_slot_level;  p->keep = keep;  return p->slot;}/* If X could be a reference to a temporary slot, mark that slot as belonging   to the to one level higher.  If X matched one of our slots, just mark that   one.  Otherwise, we can't easily predict which it is, so upgrade all of   them.  Kept slots need not be touched.   This is called when an ({...}) construct occurs and a statement   returns a value in memory.  */voidpreserve_temp_slots (x)     rtx x;{  struct temp_slot *p;  /* If X is not in memory or is at a constant address, it cannot be in     a temporary slot.  */  if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))    return;  /* First see if we can find a match.  */  for (p = temp_slots; p; p = p->next)    if (p->in_use && x == p->slot)      {	p->level--;	return;      }  /* Otherwise, preserve all non-kept slots at this level.  */  for (p = temp_slots; p; p = p->next)    if (p->in_use && p->level == temp_slot_level && ! p->keep)      p->level--;}/* Free all temporaries used so far.  This is normally called at the end   of generating code for a statement.  */voidfree_temp_slots (){  struct temp_slot *p;  for (p = temp_slots; p; p = p->next)    if (p->in_use && p->level == temp_slot_level && ! p->keep)      p->in_use = 0;}/* Push deeper into the nesting level for stack temporaries.  */voidpush_temp_slots (){  /* For GNU C++, we must allow a sequence to be emitted anywhere in     the level where the sequence was started.  By not changing levels     when the compiler is inside a sequence, the temporaries for the     sequence and the temporaries will not unwittingly conflict with     the temporaries for other sequences and/or code at that level.  */  if (in_sequence_p ())    return;  temp_slot_level++;}/* Pop a temporary nesting level.  All slots in use in the current level   are freed.  */voidpop_temp_slots (){  struct temp_slot *p;  /* See comment in push_temp_slots about why we don't change levels     in sequences.  */  if (in_sequence_p ())    return;  for (p = temp_slots; p; p = p->next)    if (p->in_use && p->level == temp_slot_level)      p->in_use = 0;  temp_slot_level--;}/* Retroactively move an auto variable from a register to a stack slot.   This is done when an address-reference to the variable is seen.  */voidput_var_into_stack (decl)     tree decl;{  register rtx reg;  register rtx new = 0;

⌨️ 快捷键说明

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