📄 integrate.c
字号:
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; /* 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 && TREE_TYPE (arg) != 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); /* Make a fresh binding contour that we can easily remove. */ pushlevel (0); expand_start_bindings (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]); } /* 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)); map->label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx)); map->label_map -= min_labelno; 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. */ map->insns_at_start = get_last_insn (); /* 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) { /* This is the good case where the parameter is in a register. If it is read-only and our argument is a constant, set up the constant equivalence. If LOC is REG_USERVAR_P, the usual case, COPY must also have that flag set if it is a register. Also, don't allow hard registers here; they might not be valid when substituted into insns. */ if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG) || (GET_CODE (copy) == REG && REG_USERVAR_P (loc) && ! REG_USERVAR_P (copy)) || (GET_CODE (copy) == REG && REGNO (copy) < FIRST_PSEUDO_REGISTER)) { temp = copy_to_mode_reg (GET_MODE (loc), copy); REG_USERVAR_P (temp) = REG_USERVAR_P (loc); 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 (loc)] = copy; } else if (GET_CODE (loc) == CONCAT) { /* This is the good case where the parameter is in a pair of separate pseudos. If it is read-only and our argument is a constant, set up the constant equivalence. If LOC is REG_USERVAR_P, the usual case, COPY must also have that flag set if it is a register. Also, don't allow hard registers here; they might not be valid when substituted into insns. */ rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc); rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc); rtx copyreal = gen_realpart (GET_MODE (locreal), copy); rtx copyimag = gen_imagpart (GET_MODE (locimag), copy); if ((GET_CODE (copyreal) != REG && GET_CODE (copyreal) != SUBREG) || (GET_CODE (copyreal) == REG && REG_USERVAR_P (locreal) && ! REG_USERVAR_P (copyreal)) || (GET_CODE (copyreal) == REG && REGNO (copyreal) < FIRST_PSEUDO_REGISTER)) { temp = copy_to_mode_reg (GET_MODE (locreal), copyreal); REG_USERVAR_P (temp) = REG_USERVAR_P (locreal); if ((CONSTANT_P (copyreal) || FIXED_BASE_PLUS_P (copyreal)) && REGNO (temp) < map->const_equiv_map_size) { map->const_equiv_map[REGNO (temp)] = copyreal; map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; } copyreal = temp; } map->reg_map[REGNO (locreal)] = copyreal; if ((GET_CODE (copyimag) != REG && GET_CODE (copyimag) != SUBREG) || (GET_CODE (copyimag) == REG && REG_USERVAR_P (locimag) && ! REG_USERVAR_P (copyimag)) || (GET_CODE (copyimag) == REG && REGNO (copyimag) < FIRST_PSEUDO_REGISTER)) { temp = copy_to_mode_reg (GET_MODE (locimag), copyimag); REG_USERVAR_P (temp) = REG_USERVAR_P (locimag); if ((CONSTANT_P (copyimag) || FIXED_BASE_PLUS_P (copyimag)) && REGNO (temp) < map->const_equiv_map_size) { map->const_equiv_map[REGNO (temp)] = copyimag; map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; } copyimag = temp; } map->reg_map[REGNO (locimag)] = copyimag; } else abort (); } /* Now do the parameters that will be placed in memory. */ for (formal = DECL_ARGUMENTS (fndecl), i = 0; formal; formal = TREE_CHAIN (formal), i++) { loc = RTVEC_ELT (arg_vector, i); if (GET_CODE (loc) == MEM /* Exclude case handled above. */ && ! (GET_CODE (XEXP (loc, 0)) == REG && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)) { rtx note = emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal)); if (note) RTX_INTEGRATED_P (note) = 1; /* Compute the address in the area we reserved and store the value there. */ temp = copy_rtx_and_substitute (loc, map); subst_constants (&temp, NULL_RTX, map); apply_change_group (); if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) temp = change_address (temp, VOIDmode, XEXP (temp, 0)); store_expr (arg_trees[i], temp, 0); } } /* Deal with the places that the function puts its result. We are driven by what is placed into DECL_RESULT. Initially, we assume that we don't have anything special handling for
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -