integrate.c

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

C
1,907
字号
  original_end = BLOCK_END_NOTE (block);  if (original_end)    {      BLOCK_END_NOTE (block) = (rtx) NOTE_SOURCE_FILE (original_end);      NOTE_SOURCE_FILE (original_end) = 0;    }  /* Process all subblocks.  */  for (subblock = BLOCK_SUBBLOCKS (block);       subblock;       subblock = TREE_CHAIN (subblock))    adjust_copied_decl_tree (subblock);}/* Make the insns and PARM_DECLs of the current function permanent   and record other information in DECL_SAVED_INSNS to allow inlining   of this function in subsequent calls.   This function is called when we are going to immediately compile   the insns for FNDECL.  The insns in maybepermanent_obstack cannot be   modified by the compilation process, so we copy all of them to   new storage and consider the new insns to be the insn chain to be   compiled.  Our caller (rest_of_compilation) saves the original   DECL_INITIAL and DECL_ARGUMENTS; here we copy them.  *//* ??? The nonlocal_label list should be adjusted also.  However, since   a function that contains a nested function never gets inlined currently,   the nonlocal_label list will always be empty, so we don't worry about   it for now.  */voidsave_for_inline_copying (fndecl)     tree fndecl;{  rtx first_insn, last_insn, insn;  rtx head, copy;  int max_labelno, min_labelno, i, len;  int max_reg;  int max_uid;  rtx first_nonparm_insn;  char *new, *new1;  rtx *new_parm_reg_stack_loc;  /* Make and emit a return-label if we have not already done so.      Do this before recording the bounds on label numbers.  */  if (return_label == 0)    {      return_label = gen_label_rtx ();      emit_label (return_label);    }  /* Get some bounds on the labels and registers used.  */  max_labelno = max_label_num ();  min_labelno = get_first_label_num ();  max_reg = max_reg_num ();  /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.     Later we set TREE_READONLY to 0 if the parm is modified inside the fn.     Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values     for the parms, prior to elimination of virtual registers.     These values are needed for substituting parms properly.  */  parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));  head = initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, 1);  if (current_function_uses_const_pool)    {      /* Replace any constant pool references with the actual constant.  We	 will put the constants back in the copy made below.  */      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))	if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')	  {	    save_constants (&PATTERN (insn));	    if (REG_NOTES (insn))	      save_constants (&REG_NOTES (insn));	  }      /* Also scan all decls, and replace any constant pool references with the	 actual constant.  */      save_constants_in_decl_trees (DECL_INITIAL (fndecl));      /* Clear out the constant pool so that we can recreate it with the	 copied constants below.  */      init_const_rtx_hash_table ();      clear_const_double_mem ();    }  max_uid = INSN_UID (head);  /* We have now allocated all that needs to be allocated permanently     on the rtx obstack.  Set our high-water mark, so that we     can free the rest of this when the time comes.  */  preserve_data ();  /* Copy the chain insns of this function.     Install the copied chain as the insns of this function,     for continued compilation;     the original chain is recorded as the DECL_SAVED_INSNS     for inlining future calls.  */  /* If there are insns that copy parms from the stack into pseudo registers,     those insns are not copied.  `expand_inline_function' must     emit the correct code to handle such things.  */  insn = get_insns ();  if (GET_CODE (insn) != NOTE)    abort ();  first_insn = rtx_alloc (NOTE);  NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);  NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);  INSN_UID (first_insn) = INSN_UID (insn);  PREV_INSN (first_insn) = NULL;  NEXT_INSN (first_insn) = NULL;  last_insn = first_insn;  /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy.     Make these new rtx's now, and install them in regno_reg_rtx, so they     will be the official pseudo-reg rtx's for the rest of compilation.  */  reg_map = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));  len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);  for (i = max_reg - 1; i > LAST_VIRTUAL_REGISTER; i--)    reg_map[i] = (rtx)obstack_copy (function_maybepermanent_obstack,				    regno_reg_rtx[i], len);  regno_reg_rtx = reg_map;  /* Put copies of all the virtual register rtx into the new regno_reg_rtx.  */  regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;  regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;  regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;  regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;  /* Likewise each label rtx must have a unique rtx as its copy.  */  /* We used to use alloca here, but the size of what it would try to     allocate would occasionally cause it to exceed the stack limit and     cause unpredictable core dumps.  Some examples were > 2Mb in size.  */  label_map = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));  for (i = min_labelno; i < max_labelno; i++)    label_map[i] = gen_label_rtx ();  /* Likewise for parm_reg_stack_slot.  */  new_parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx));  for (i = 0; i < max_parm_reg; i++)    new_parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);  parm_reg_stack_loc = new_parm_reg_stack_loc;  /* Record the mapping of old insns to copied insns.  */  insn_map = (rtx *) alloca (max_uid * sizeof (rtx));  bzero ((char *) insn_map, max_uid * sizeof (rtx));  /* Get the insn which signals the end of parameter setup code.  */  first_nonparm_insn = get_first_nonparm_insn ();  /* Copy any entries in regno_reg_rtx or DECL_RTLs that reference MEM     (the former occurs when a variable has its address taken)     since these may be shared and can be changed by virtual     register instantiation.  DECL_RTL values for our arguments     have already been copied by initialize_for_inline.  */  for (i = LAST_VIRTUAL_REGISTER + 1; i < max_reg; i++)    if (GET_CODE (regno_reg_rtx[i]) == MEM)      XEXP (regno_reg_rtx[i], 0)	= copy_for_inline (XEXP (regno_reg_rtx[i], 0));  /* Copy the tree of subblocks of the function, and the decls in them.     We will use the copy for compiling this function, then restore the original     subblocks and decls for use when inlining this function.     Several parts of the compiler modify BLOCK trees.  In particular,     instantiate_virtual_regs will instantiate any virtual regs     mentioned in the DECL_RTLs of the decls, and loop     unrolling will replicate any BLOCK trees inside an unrolled loop.     The modified subblocks or DECL_RTLs would be incorrect for the original rtl     which we will use for inlining.  The rtl might even contain pseudoregs     whose space has been freed.  */  DECL_INITIAL (fndecl) = copy_decl_tree (DECL_INITIAL (fndecl));  DECL_ARGUMENTS (fndecl) = copy_decl_list (DECL_ARGUMENTS (fndecl));  /* Now copy each DECL_RTL which is a MEM,     so it is safe to modify their addresses.  */  copy_decl_rtls (DECL_INITIAL (fndecl));  /* The fndecl node acts as its own progenitor, so mark it as such.  */  DECL_ABSTRACT_ORIGIN (fndecl) = fndecl;  /* Now copy the chain of insns.  Do this twice.  The first copy the insn     itself and its body.  The second time copy of REG_NOTES.  This is because     a REG_NOTE may have a forward pointer to another insn.  */  for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))    {      orig_asm_operands_vector = 0;      if (insn == first_nonparm_insn)	in_nonparm_insns = 1;      switch (GET_CODE (insn))	{	case NOTE:	  /* No need to keep these.  */	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)	    continue;	  copy = rtx_alloc (NOTE);	  NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);	  if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_END)	    NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);	  else	    {	      NOTE_SOURCE_FILE (insn) = (char *) copy;	      NOTE_SOURCE_FILE (copy) = 0;	    }	  if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG	      || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)	    {	      /* We have to forward these both to match the new exception		 region.  */	      NOTE_BLOCK_NUMBER (copy)		= CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]);	      	    }	  RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);	  break;	case INSN:	case JUMP_INSN:	case CALL_INSN:	  copy = rtx_alloc (GET_CODE (insn));	  if (GET_CODE (insn) == CALL_INSN)	    CALL_INSN_FUNCTION_USAGE (copy)	      = copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn));	  PATTERN (copy) = copy_for_inline (PATTERN (insn));	  INSN_CODE (copy) = -1;	  LOG_LINKS (copy) = NULL_RTX;	  RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);	  break;	case CODE_LABEL:	  copy = label_map[CODE_LABEL_NUMBER (insn)];	  LABEL_NAME (copy) = LABEL_NAME (insn);	  break;	case BARRIER:	  copy = rtx_alloc (BARRIER);	  break;	default:	  abort ();	}      INSN_UID (copy) = INSN_UID (insn);      insn_map[INSN_UID (insn)] = copy;      NEXT_INSN (last_insn) = copy;      PREV_INSN (copy) = last_insn;      last_insn = copy;    }  adjust_copied_decl_tree (DECL_INITIAL (fndecl));  /* Now copy the REG_NOTES.  */  for (insn = NEXT_INSN (get_insns ()); insn; insn = NEXT_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'	&& insn_map[INSN_UID(insn)])      REG_NOTES (insn_map[INSN_UID (insn)])	= copy_for_inline (REG_NOTES (insn));  NEXT_INSN (last_insn) = NULL;  finish_inline (fndecl, head);  /* Make new versions of the register tables.  */  new = (char *) savealloc (regno_pointer_flag_length);  bcopy (regno_pointer_flag, new, regno_pointer_flag_length);  new1 = (char *) savealloc (regno_pointer_flag_length);  bcopy (regno_pointer_align, new1, regno_pointer_flag_length);  regno_pointer_flag = new;  regno_pointer_align = new1;  set_new_first_and_last_insn (first_insn, last_insn);  if (label_map)    free (label_map);}/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field.   For example, this can copy a list made of TREE_LIST nodes.  While copying,   for each node copied which doesn't already have is DECL_ABSTRACT_ORIGIN   set to some non-zero value, set the DECL_ABSTRACT_ORIGIN of the copy to   point to the corresponding (abstract) original node.  */static treecopy_decl_list (list)     tree list;{  tree head;  register tree prev, next;  if (list == 0)    return 0;  head = prev = copy_node (list);  if (DECL_ABSTRACT_ORIGIN (head) == NULL_TREE)    DECL_ABSTRACT_ORIGIN (head) = list;  next = TREE_CHAIN (list);  while (next)    {      register tree copy;      copy = copy_node (next);      if (DECL_ABSTRACT_ORIGIN (copy) == NULL_TREE)	DECL_ABSTRACT_ORIGIN (copy) = next;      TREE_CHAIN (prev) = copy;      prev = copy;      next = TREE_CHAIN (next);    }  return head;}/* Make a copy of the entire tree of blocks BLOCK, and return it.  */static treecopy_decl_tree (block)     tree block;{  tree t, vars, subblocks;  vars = copy_decl_list (BLOCK_VARS (block));  subblocks = 0;  /* Process all subblocks.  */  for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t))    {      tree copy = copy_decl_tree (t);      TREE_CHAIN (copy) = subblocks;      subblocks = copy;    }  t = copy_node (block);  BLOCK_VARS (t) = vars;  BLOCK_SUBBLOCKS (t) = nreverse (subblocks);  /* If the BLOCK being cloned is already marked as having been instantiated     from something else, then leave that `origin' marking alone.  Otherwise,     mark the clone as having originated from the BLOCK we are cloning.  */  if (BLOCK_ABSTRACT_ORIGIN (t) == NULL_TREE)    BLOCK_ABSTRACT_ORIGIN (t) = block;  return t;}/* Copy DECL_RTLs in all decls in the given BLOCK node.  */static voidcopy_decl_rtls (block)     tree block;{  tree t;  for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t))    if (DECL_RTL (t) && GET_CODE (DECL_RTL (t)) == MEM)      DECL_RTL (t) = copy_for_inline (DECL_RTL (t));  /* Process all subblocks.  */  for (t = BLOCK_SUBBLOCKS (block); t; t = TREE_CHAIN (t))    copy_decl_rtls (t);}/* Make the insns and PARM_DECLs of the current function permanent   and record other information in DECL_SAVED_INSNS to allow inlining   of this function in subsequent calls.

⌨️ 快捷键说明

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