📄 integrate.c
字号:
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, structure_value_addr); map->reg_map[REGNO (XEXP (loc, 0))] = temp; if ((CONSTANT_P (structure_value_addr) || (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). */ enum machine_mode arriving_mode = TYPE_MODE (TREE_TYPE (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) 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; } /* 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) { 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 insn but whose branch direction is now know, we must do something special. */ if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value) {#ifdef HAVE_cc0 /* The previous insn set cc0 for us. So delete it. */ delete_insn (PREV_INSN (copy));#endif /* If this is now a no-op, delete it. */ if (map->last_pc_value == pc_rtx) { delete_insn (copy); copy = 0; } else /* Otherwise, this is unconditional jump so we must put a BARRIER after it. We could do some dead code elimination here, but jump.c will do it just as well. */ emit_barrier (); } break; case CALL_INSN: pattern = copy_rtx_and_substitute (PATTERN (insn), map); copy = emit_call_insn (pattern); /* Because the USAGE information potentially contains objects other than hard registers, we need to copy it. */ CALL_INSN_FUNCTION_USAGE (copy) = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);#ifdef HAVE_cc0 if (cc0_insn) try_constants (cc0_insn, map); cc0_insn = 0;#endif try_constants (copy, map); /* Be lazy and assume CALL_INSNs clobber all hard registers. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) map->const_equiv_map[i] = 0; break; case CODE_LABEL: copy = emit_label (map->label_map[CODE_LABEL_NUMBER (insn)]); LABEL_NAME (copy) = LABEL_NAME (insn); map->const_age++; break; case BARRIER: copy = emit_barrier (); break; case NOTE: /* It is important to discard function-end and function-beg notes, so we have only one of each in the current function. Also, NOTE_INSN_DELETED notes aren't useful (save_for_inline deleted these in the copy used for continuing compilation, not the copy used for inlining). */ if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED) copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn)); else copy = 0; break; default: abort (); break; } if (copy) RTX_INTEGRATED_P (copy) = 1; map->insn_map[INSN_UID (insn)] = copy; } /* Now copy the REG_NOTES. Increment const_age, so that only constants from parameters can be substituted in. These are the only ones that are valid across the entire function. */ map->const_age++; for (insn = insns; insn; insn = NEXT_INSN (insn)) if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' && map->insn_map[INSN_UID (insn)] && REG_NOTES (insn)) { rtx tem = copy_rtx_and_substitute (REG_NOTES (insn), map); /* We must also do subst_constants, in case one of our parameters has const type and constant value. */ subst_constants (&tem, NULL_RTX, map); apply_change_group (); REG_NOTES (map->insn_map[INSN_UID (insn)]) = tem; } if (local_return_label) emit_label (local_return_label); /* Restore the stack pointer if we saved it above. */ if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_CALLS_ALLOCA) emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX); /* Make copies of the decls of the symbols in the inline function, so that the copies of the variables get declared in the current function. Set up things so that lookup_static_chain knows that to interpret registers in SAVE_EXPRs for TYPE_SIZEs as local. */ inline_function_decl = fndecl; integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector); integrate_decl_tree ((tree) ORIGINAL_DECL_INITIAL (header), 0, map); inline_function_decl = 0; /* End the scope containing the copied formal parameter variables and copied LABEL_DECLs. */ expand_end_bindings (getdecls (), 1, 1); block = poplevel (1, 1, 0); BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL ? fndecl : DECL_ABSTRACT_ORIGIN (fndecl)); poplevel (0, 0, 0); emit_line_note (input_filename, lineno); if (structure_value_addr) { target = gen_rtx (MEM, TYPE_MODE (type), memory_address (TYPE_MODE (type), structure_value_addr)); MEM_IN_STRUCT_P (target) = 1; } return target;}/* Given a chain of PARM_DECLs, ARGS, copy each decl into a VAR_DECL, push all of those decls and give each one the corresponding home. */static voidintegrate_parm_decls (args, map, arg_vector) tree args; struct inline_remap *map; rtvec arg_vector;{ register tree tail; register int i; for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++) { register tree decl = build_decl (VAR_DECL, DECL_NAME (tail), TREE_TYPE (tail)); rtx new_decl_rtl = copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map); DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (tail); /* We really should be setting DECL_INCOMING_RTL to something reasonable here, but that's going
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -