integrate.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,907 行 · 第 1/5 页
C
1,907 行
{ /* 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 REG_FUNCTION_RETURN_VALUE_P. */ map->inline_target = 0; loc = DECL_RTL (DECL_RESULT (fndecl)); if (TYPE_MODE (type) == VOIDmode) /* There is no return value to worry about. */ ; else if (GET_CODE (loc) == MEM) { if (! structure_value_addr || ! aggregate_value_p (DECL_RESULT (fndecl))) abort (); /* Pass the function the address in which to return a structure value. Note that a constructor can cause someone to call us with STRUCTURE_VALUE_ADDR, but the initialization takes place via the first parameter, rather than the struct return address. We have two cases: If the address is a simple register indirect, use the mapping mechanism to point that register to our structure return address. Otherwise, store the structure return value into the place that it will be referenced from. */ if (GET_CODE (XEXP (loc, 0)) == REG) { temp = force_reg (Pmode, force_operand (structure_value_addr, NULL_RTX)); map->reg_map[REGNO (XEXP (loc, 0))] = temp; if ((CONSTANT_P (structure_value_addr) || GET_CODE (structure_value_addr) == ADDRESSOF || (GET_CODE (structure_value_addr) == PLUS && XEXP (structure_value_addr, 0) == virtual_stack_vars_rtx && GET_CODE (XEXP (structure_value_addr, 1)) == CONST_INT)) && REGNO (temp) < map->const_equiv_map_size) { map->const_equiv_map[REGNO (temp)] = structure_value_addr; map->const_age_map[REGNO (temp)] = CONST_AGE_PARM; } } else { temp = copy_rtx_and_substitute (loc, map); subst_constants (&temp, NULL_RTX, map); apply_change_group (); emit_move_insn (temp, structure_value_addr); } } else if (ignore) /* We will ignore the result value, so don't look at its structure. Note that preparations for an aggregate return value do need to be made (above) even if it will be ignored. */ ; else if (GET_CODE (loc) == REG) { /* The function returns an object in a register and we use the return value. Set up our target for remapping. */ /* Machine mode function was declared to return. */ enum machine_mode departing_mode = TYPE_MODE (type); /* (Possibly wider) machine mode it actually computes (for the sake of callers that fail to declare it right). We have to use the mode of the result's RTL, rather than its type, since expand_function_start may have promoted it. */ enum machine_mode arriving_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl))); rtx reg_to_map; /* Don't use MEMs as direct targets because on some machines substituting a MEM for a REG makes invalid insns. Let the combiner substitute the MEM if that is valid. */ if (target == 0 || GET_CODE (target) != REG || GET_MODE (target) != departing_mode) target = gen_reg_rtx (departing_mode); /* If function's value was promoted before return, avoid machine mode mismatch when we substitute INLINE_TARGET. But TARGET is what we will return to the caller. */ if (arriving_mode != departing_mode) { /* Avoid creating a paradoxical subreg wider than BITS_PER_WORD, since that is illegal. */ if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD) { if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode), GET_MODE_BITSIZE (arriving_mode))) /* Maybe could be handled by using convert_move () ? */ abort (); reg_to_map = gen_reg_rtx (arriving_mode); target = gen_lowpart (departing_mode, reg_to_map); } else reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0); } else reg_to_map = target; /* Usually, the result value is the machine's return register. Sometimes it may be a pseudo. Handle both cases. */ if (REG_FUNCTION_VALUE_P (loc)) map->inline_target = reg_to_map; else map->reg_map[REGNO (loc)] = reg_to_map; } else abort (); /* Make a fresh binding contour that we can easily remove. Do this after expanding our arguments so cleanups are properly scoped. */ pushlevel (0); expand_start_bindings (0); /* Make new label equivalences for the labels in the called function. */ for (i = min_labelno; i < max_labelno; i++) map->label_map[i] = gen_label_rtx (); /* Perform postincrements before actually calling the function. */ emit_queue (); /* Clean up stack so that variables might have smaller offsets. */ do_pending_stack_adjust (); /* Save a copy of the location of const_equiv_map for mark_stores, called via note_stores. */ global_const_equiv_map = map->const_equiv_map; global_const_equiv_map_size = map->const_equiv_map_size; /* If the called function does an alloca, save and restore the stack pointer around the call. This saves stack space, but also is required if this inline is being done between two pushes. */ if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_CALLS_ALLOCA) emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX); /* Now copy the insns one by one. Do this in two passes, first the insns and then their REG_NOTES, just like save_for_inline. */ /* This loop is very similar to the loop in copy_loop_body in unroll.c. */ for (insn = insns; insn; insn = NEXT_INSN (insn)) { rtx copy, pattern, set; map->orig_asm_operands_vector = 0; switch (GET_CODE (insn)) { case INSN: pattern = PATTERN (insn); set = single_set (insn); copy = 0; if (GET_CODE (pattern) == USE && GET_CODE (XEXP (pattern, 0)) == REG && REG_FUNCTION_VALUE_P (XEXP (pattern, 0))) /* The (USE (REG n)) at return from the function should be ignored since we are changing (REG n) into inline_target. */ break; /* Ignore setting a function value that we don't want to use. */ if (map->inline_target == 0 && set != 0 && GET_CODE (SET_DEST (set)) == REG && REG_FUNCTION_VALUE_P (SET_DEST (set))) { if (volatile_refs_p (SET_SRC (set))) { rtx new_set; /* If we must not delete the source, load it into a new temporary. */ copy = emit_insn (copy_rtx_and_substitute (pattern, map)); new_set = single_set (copy); if (new_set == 0) abort (); SET_DEST (new_set) = gen_reg_rtx (GET_MODE (SET_DEST (new_set))); } /* If the source and destination are the same and it has a note on it, keep the insn. */ else if (rtx_equal_p (SET_DEST (set), SET_SRC (set)) && REG_NOTES (insn) != 0) copy = emit_insn (copy_rtx_and_substitute (pattern, map)); else break; } /* If this is setting the static chain rtx, omit it. */ else if (static_chain_value != 0 && set != 0 && GET_CODE (SET_DEST (set)) == REG && rtx_equal_p (SET_DEST (set), static_chain_incoming_rtx)) break; /* If this is setting the static chain pseudo, set it from the value we want to give it instead. */ else if (static_chain_value != 0 && set != 0 && rtx_equal_p (SET_SRC (set), static_chain_incoming_rtx)) { rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map); copy = emit_move_insn (newdest, static_chain_value); static_chain_value = 0; } else copy = emit_insn (copy_rtx_and_substitute (pattern, map)); /* REG_NOTES will be copied later. */#ifdef HAVE_cc0 /* If this insn is setting CC0, it may need to look at the insn that uses CC0 to see what type of insn it is. In that case, the call to recog via validate_change will fail. So don't substitute constants here. Instead, do it when we emit the following insn. For example, see the pyr.md file. That machine has signed and unsigned compares. The compare patterns must check the following branch insn to see which what kind of compare to emit. If the previous insn set CC0, substitute constants on it as well. */ if (sets_cc0_p (PATTERN (copy)) != 0) cc0_insn = copy; else { if (cc0_insn) try_constants (cc0_insn, map); cc0_insn = 0; try_constants (copy, map); }#else try_constants (copy, map);#endif break; case JUMP_INSN: if (GET_CODE (PATTERN (insn)) == RETURN || (GET_CODE (PATTERN (insn)) == PARALLEL && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN)) { if (local_return_label == 0) local_return_label = gen_label_rtx (); pattern = gen_jump (local_return_label); } else pattern = copy_rtx_and_substitute (PATTERN (insn), map); copy = emit_jump_insn (pattern);#ifdef HAVE_cc0 if (cc0_insn) try_constants (cc0_insn, map); cc0_insn = 0;#endif try_constants (copy, map); /* If this used to be a conditional jump in
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?