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 (®_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 + -
显示快捷键?