integrate.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,907 行 · 第 1/5 页
C
1,907 行
XEXP (x, 0) = XEXP (x, 1); XEXP (x, 1) = t; } break;#endif default: break; } /* Replace this rtx with a copy of itself. */ x = rtx_alloc (code); bcopy ((char *) orig, (char *) x, (sizeof (*x) - sizeof (x->fld) + sizeof (x->fld[0]) * GET_RTX_LENGTH (code))); /* Now scan the subexpressions recursively. We can store any replaced subexpressions directly into X since we know X is not shared! Any vectors in X must be copied if X was copied. */ format_ptr = GET_RTX_FORMAT (code); for (i = 0; i < GET_RTX_LENGTH (code); i++) { switch (*format_ptr++) { case 'e': XEXP (x, i) = copy_for_inline (XEXP (x, i)); break; case 'u': /* Change any references to old-insns to point to the corresponding copied insns. */ XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))]; break; case 'E': if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0) { register int j; XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem); for (j = 0; j < XVECLEN (x, i); j++) XVECEXP (x, i, j) = copy_for_inline (XVECEXP (x, i, j)); } break; } } if (code == ASM_OPERANDS && orig_asm_operands_vector == 0) { orig_asm_operands_vector = XVEC (orig, 3); copy_asm_operands_vector = XVEC (x, 3); copy_asm_constraints_vector = XVEC (x, 4); } return x;}/* Unfortunately, we need a global copy of const_equiv map for communication with a function called from note_stores. Be *very* careful that this is used properly in the presence of recursion. */rtx *global_const_equiv_map;int global_const_equiv_map_size;#define FIXED_BASE_PLUS_P(X) \ (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ && GET_CODE (XEXP (X, 0)) == REG \ && REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER \ && REGNO (XEXP (X, 0)) <= LAST_VIRTUAL_REGISTER)/* Integrate the procedure defined by FNDECL. Note that this function may wind up calling itself. Since the static variables are not reentrant, we do not assign them until after the possibility of recursion is eliminated. If IGNORE is nonzero, do not produce a value. Otherwise store the value in TARGET if it is nonzero and that is convenient. Value is: (rtx)-1 if we could not substitute the function 0 if we substituted it and it does not produce a value else an rtx for where the value is stored. */rtxexpand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr) tree fndecl, parms; rtx target; int ignore; tree type; rtx structure_value_addr;{ tree formal, actual, block; rtx header = DECL_SAVED_INSNS (fndecl); rtx insns = FIRST_FUNCTION_INSN (header); rtx parm_insns = FIRST_PARM_INSN (header); tree *arg_trees; rtx *arg_vals; rtx insn; int max_regno; register int i; int min_labelno = FIRST_LABELNO (header); int max_labelno = LAST_LABELNO (header); int nargs; rtx local_return_label = 0; rtx loc; rtx stack_save = 0; rtx temp; struct inline_remap *map; rtx cc0_insn = 0; rtvec arg_vector = ORIGINAL_ARG_VECTOR (header); rtx static_chain_value = 0; /* The pointer used to track the true location of the memory used for MAP->LABEL_MAP. */ rtx *real_label_map = 0; /* Allow for equivalences of the pseudos we make for virtual fp and ap. */ max_regno = MAX_REGNUM (header) + 3; if (max_regno < FIRST_PSEUDO_REGISTER) abort (); nargs = list_length (DECL_ARGUMENTS (fndecl)); /* Check that the parms type match and that sufficient arguments were passed. Since the appropriate conversions or default promotions have already been applied, the machine modes should match exactly. */ for (formal = DECL_ARGUMENTS (fndecl), actual = parms; formal; formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual)) { tree arg; enum machine_mode mode; if (actual == 0) return (rtx) (HOST_WIDE_INT) -1; arg = TREE_VALUE (actual); mode = TYPE_MODE (DECL_ARG_TYPE (formal)); if (mode != TYPE_MODE (TREE_TYPE (arg)) /* If they are block mode, the types should match exactly. They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE, which could happen if the parameter has incomplete type. */ || (mode == BLKmode && (TYPE_MAIN_VARIANT (TREE_TYPE (arg)) != TYPE_MAIN_VARIANT (TREE_TYPE (formal))))) return (rtx) (HOST_WIDE_INT) -1; } /* Extra arguments are valid, but will be ignored below, so we must evaluate them here for side-effects. */ for (; actual; actual = TREE_CHAIN (actual)) expand_expr (TREE_VALUE (actual), const0_rtx, TYPE_MODE (TREE_TYPE (TREE_VALUE (actual))), 0); /* Make a binding contour to keep inline cleanups called at outer function-scope level from looking like they are shadowing parameter declarations. */ pushlevel (0); /* Expand the function arguments. Do this first so that any new registers get created before we allocate the maps. */ arg_vals = (rtx *) alloca (nargs * sizeof (rtx)); arg_trees = (tree *) alloca (nargs * sizeof (tree)); for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0; formal; formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++) { /* Actual parameter, converted to the type of the argument within the function. */ tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual)); /* Mode of the variable used within the function. */ enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal)); int invisiref = 0; arg_trees[i] = arg; loc = RTVEC_ELT (arg_vector, i); /* If this is an object passed by invisible reference, we copy the object into a stack slot and save its address. If this will go into memory, we do nothing now. Otherwise, we just expand the argument. */ if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) { rtx stack_slot = assign_stack_temp (TYPE_MODE (TREE_TYPE (arg)), int_size_in_bytes (TREE_TYPE (arg)), 1); MEM_IN_STRUCT_P (stack_slot) = AGGREGATE_TYPE_P (TREE_TYPE (arg)); store_expr (arg, stack_slot, 0); arg_vals[i] = XEXP (stack_slot, 0); invisiref = 1; } else if (GET_CODE (loc) != MEM) { if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg))) /* The mode if LOC and ARG can differ if LOC was a variable that had its mode promoted via PROMOTED_MODE. */ arg_vals[i] = convert_modes (GET_MODE (loc), TYPE_MODE (TREE_TYPE (arg)), expand_expr (arg, NULL_RTX, mode, EXPAND_SUM), TREE_UNSIGNED (TREE_TYPE (formal))); else arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM); } else arg_vals[i] = 0; if (arg_vals[i] != 0 && (! TREE_READONLY (formal) /* If the parameter is not read-only, copy our argument through a register. Also, we cannot use ARG_VALS[I] if it overlaps TARGET in any way. In the inline function, they will likely be two different pseudos, and `safe_from_p' will make all sorts of smart assumptions about their not conflicting. But if ARG_VALS[I] overlaps TARGET, these assumptions are wrong, so put ARG_VALS[I] into a fresh register. Don't worry about invisible references, since their stack temps will never overlap the target. */ || (target != 0 && ! invisiref && (GET_CODE (arg_vals[i]) == REG || GET_CODE (arg_vals[i]) == SUBREG || GET_CODE (arg_vals[i]) == MEM) && reg_overlap_mentioned_p (arg_vals[i], target)) /* ??? We must always copy a SUBREG into a REG, because it might get substituted into an address, and not all ports correctly handle SUBREGs in addresses. */ || (GET_CODE (arg_vals[i]) == SUBREG))) arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]); if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG && TREE_CODE (TREE_TYPE (formal)) == POINTER_TYPE) mark_reg_pointer (arg_vals[i], (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal))) / BITS_PER_UNIT)); } /* Allocate the structures we use to remap things. */ map = (struct inline_remap *) alloca (sizeof (struct inline_remap)); map->fndecl = fndecl; map->reg_map = (rtx *) alloca (max_regno * sizeof (rtx)); bzero ((char *) map->reg_map, max_regno * sizeof (rtx)); /* 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. */ real_label_map = (rtx *) xmalloc ((max_labelno) * sizeof (rtx)); map->label_map = real_label_map; map->insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx)); bzero ((char *) map->insn_map, INSN_UID (header) * sizeof (rtx)); map->min_insnno = 0; map->max_insnno = INSN_UID (header); map->integrating = 1; /* const_equiv_map maps pseudos in our routine to constants, so it needs to be large enough for all our pseudos. This is the number we are currently using plus the number in the called routine, plus 15 for each arg, five to compute the virtual frame pointer, and five for the return value. This should be enough for most cases. We do not reference entries outside the range of the map. ??? These numbers are quite arbitrary and were obtained by experimentation. At some point, we should try to allocate the table after all the parameters are set up so we an more accurately estimate the number of pseudos we will need. */ map->const_equiv_map_size = max_reg_num () + (max_regno - FIRST_PSEUDO_REGISTER) + 15 * nargs + 10; map->const_equiv_map = (rtx *)alloca (map->const_equiv_map_size * sizeof (rtx)); bzero ((char *) map->const_equiv_map, map->const_equiv_map_size * sizeof (rtx)); map->const_age_map = (unsigned *)alloca (map->const_equiv_map_size * sizeof (unsigned)); bzero ((char *) map->const_age_map, map->const_equiv_map_size * sizeof (unsigned)); map->const_age = 0; /* Record the current insn in case we have to set up pointers to frame and argument memory blocks. If there are no insns yet, add a dummy insn that can be used as an insertion point. */ map->insns_at_start = get_last_insn (); if (map->insns_at_start == 0) map->insns_at_start = emit_note (NULL_PTR, NOTE_INSN_DELETED); map->regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (header); map->regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (header); /* Update the outgoing argument size to allow for those in the inlined function. */ if (OUTGOING_ARGS_SIZE (header) > current_function_outgoing_args_size) current_function_outgoing_args_size = OUTGOING_ARGS_SIZE (header); /* If the inline function needs to make PIC references, that means that this function's PIC offset table must be used. */ if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE) current_function_uses_pic_offset_table = 1; /* If this function needs a context, set it up. */ if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_NEEDS_CONTEXT) static_chain_value = lookup_static_chain (fndecl); if (GET_CODE (parm_insns) == NOTE && NOTE_LINE_NUMBER (parm_insns) > 0) { rtx note = emit_note (NOTE_SOURCE_FILE (parm_insns), NOTE_LINE_NUMBER (parm_insns)); if (note) RTX_INTEGRATED_P (note) = 1; } /* Process each argument. For each, set up things so that the function's reference to the argument will refer to the argument being passed. We only replace REG with REG here. Any simplifications are done via const_equiv_map. We make two passes: In the first, we deal with parameters that will be placed into registers, since we need to ensure that the allocated register number fits in const_equiv_map. Then we store all non-register parameters into their memory location. */ /* Don't try to free temp stack slots here, because we may put one of the parameters into a temp stack slot. */ for (i = 0; i < nargs; i++) { rtx copy = arg_vals[i]; loc = RTVEC_ELT (arg_vector, i); /* There are three cases, each handled separately. */ if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) { /* This must be an object passed by invisible reference (it could also be a variable-sized object, but we forbid inlining functions with variable-sized arguments). COPY is the address of the actual value (this computation will cause it to be copied). We map that address for the register, noting the actual address as an equivalent in case it can be substituted into the insns. */ if (GET_CODE (copy) != REG) { temp = copy_addr_to_reg (copy); if ((CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy)) && REGNO (temp) < map->const_equiv_map_size) { map->const_equiv_map[REGNO (temp)] = copy; map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; } copy = temp; } map->reg_map[REGNO (XEXP (loc, 0))] = copy; } else if (GET_CODE (loc) == MEM) { /* This is the case of a parameter that lives in memory. It will live in the block we allocate in the called routine's frame that simulates the incoming argument area. Do nothing now; we will call store_expr later. */ ; } else if (GET_CODE (loc) == REG)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?