-\f
-#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)
-
-/* Called to set up a mapping for the case where a 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. */
-static void
-process_reg_param (map, loc, copy)
- struct inline_remap *map;
- rtx loc, copy;
-{
- 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))
- {
- rtx 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))
- SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM);
- copy = temp;
- }
- map->reg_map[REGNO (loc)] = copy;
-}
-
-/* Compare two BLOCKs for qsort. The key we sort on is the
- BLOCK_ABSTRACT_ORIGIN of the blocks. */
-
-static int
-compare_blocks (v1, v2)
- const PTR v1;
- const PTR v2;
-{
- tree b1 = *((const tree *) v1);
- tree b2 = *((const tree *) v2);
-
- return ((char *) BLOCK_ABSTRACT_ORIGIN (b1)
- - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
-}
-
-/* Compare two BLOCKs for bsearch. The first pointer corresponds to
- an original block; the second to a remapped equivalent. */
-
-static int
-find_block (v1, v2)
- const PTR v1;
- const PTR v2;
-{
- const union tree_node *b1 = (const union tree_node *) v1;
- tree b2 = *((const tree *) v2);
-
- return ((const char *) b1 - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
-}
-
-/* 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. */
-
-rtx
-expand_inline_function (fndecl, parms, target, ignore, type,
- structure_value_addr)
- tree fndecl, parms;
- rtx target;
- int ignore;
- tree type;
- rtx structure_value_addr;
-{
- struct function *inlining_previous;
- struct function *inl_f = DECL_SAVED_INSNS (fndecl);
- tree formal, actual, block;
- rtx parm_insns = inl_f->emit->x_first_insn;
- rtx insns = (inl_f->inl_last_parm_insn
- ? NEXT_INSN (inl_f->inl_last_parm_insn)
- : parm_insns);
- tree *arg_trees;
- rtx *arg_vals;
- int max_regno;
- int i;
- int min_labelno = inl_f->emit->x_first_label_num;
- int max_labelno = inl_f->inl_max_label_num;
- int nargs;
- rtx loc;
- rtx stack_save = 0;
- rtx temp;
- struct inline_remap *map = 0;
- rtvec arg_vector = (rtvec) inl_f->original_arg_vector;
- rtx static_chain_value = 0;
- int inl_max_uid;
- int eh_region_offset;
-
- /* 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 = inl_f->emit->x_reg_rtx_no + 3;
- if (max_regno < FIRST_PSEUDO_REGISTER)
- abort ();
-
- /* Pull out the decl for the function definition; fndecl may be a
- local declaration, which would break DECL_ABSTRACT_ORIGIN. */
- fndecl = inl_f->decl;
-
- nargs = list_length (DECL_ARGUMENTS (fndecl));
-
- if (cfun->preferred_stack_boundary < inl_f->preferred_stack_boundary)
- cfun->preferred_stack_boundary = inl_f->preferred_stack_boundary;
-
- /* 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 (arg == error_mark_node
- || 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);
-
- /* Expand the function arguments. Do this first so that any
- new registers get created before we allocate the maps. */
-
- arg_vals = (rtx *) xmalloc (nargs * sizeof (rtx));
- arg_trees = (tree *) xmalloc (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_temp (TREE_TYPE (arg), 1, 1, 1);
-
- 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)))
- {
- int unsignedp = TREE_UNSIGNED (TREE_TYPE (formal));
- enum machine_mode pmode = TYPE_MODE (TREE_TYPE (formal));
-
- pmode = promote_mode (TREE_TYPE (formal), pmode,
- &unsignedp, 0);
-
- if (GET_MODE (loc) != pmode)
- abort ();
-
- /* 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 (pmode,
- TYPE_MODE (TREE_TYPE (arg)),
- expand_expr (arg, NULL_RTX, mode,
- EXPAND_SUM),
- unsignedp);
- }
- 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
- && POINTER_TYPE_P (TREE_TYPE (formal)))
- mark_reg_pointer (arg_vals[i],
- TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal))));
- }
-
- /* Allocate the structures we use to remap things. */
-
- map = (struct inline_remap *) xcalloc (1, sizeof (struct inline_remap));
- map->fndecl = fndecl;
-
- VARRAY_TREE_INIT (map->block_map, 10, "block_map");
- map->reg_map = (rtx *) xcalloc (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->local_return_label = NULL_RTX;
-
- inl_max_uid = (inl_f->emit->x_cur_insn_uid + 1);
- map->insn_map = (rtx *) xcalloc (inl_max_uid, sizeof (rtx));
- map->min_insnno = 0;
- map->max_insnno = inl_max_uid;
-
- map->integrating = 1;
- map->compare_src = NULL_RTX;
- map->compare_mode = VOIDmode;
-
- /* const_equiv_varray 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. */
-
- VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray,
- (max_reg_num ()
- + (max_regno - FIRST_PSEUDO_REGISTER)
- + 15 * nargs
- + 10),
- "expand_inline_function");
- 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, NOTE_INSN_DELETED);
-
- map->regno_pointer_align = inl_f->emit->regno_pointer_align;
- map->x_regno_reg_rtx = inl_f->emit->x_regno_reg_rtx;
-
- /* Update the outgoing argument size to allow for those in the inlined
- function. */
- if (inl_f->outgoing_args_size > current_function_outgoing_args_size)
- current_function_outgoing_args_size = inl_f->outgoing_args_size;
-
- /* If the inline function needs to make PIC references, that means
- that this function's PIC offset table must be used. */
- if (inl_f->uses_pic_offset_table)
- current_function_uses_pic_offset_table = 1;
-
- /* If this function needs a context, set it up. */
- if (inl_f->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))
- SET_CONST_EQUIV_DATA (map, temp, copy, 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
- with the parameter now; we will call store_expr later. In
- this case, however, we must ensure that the virtual stack and
- incoming arg rtx values are expanded now so that we can be
- sure we have enough slots in the const equiv map since the
- store_expr call can easily blow the size estimate. */
- if (DECL_SAVED_INSNS (fndecl)->args_size != 0)
- copy_rtx_and_substitute (virtual_incoming_args_rtx, map, 0);
- }
- else if (GET_CODE (loc) == REG)
- process_reg_param (map, loc, copy);
- else if (GET_CODE (loc) == CONCAT)
- {
- 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);
-
- process_reg_param (map, locreal, copyreal);
- process_reg_param (map, locimag, copyimag);
- }
- else
- abort ();
- }
-
- /* Tell copy_rtx_and_substitute to handle constant pool SYMBOL_REFs
- specially. This function can be called recursively, so we need to
- save the previous value. */
- inlining_previous = inlining;
- inlining = inl_f;
-
- /* 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, 1);
- subst_constants (&temp, NULL_RTX, map, 1);
- 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_SET_P (DECL_RESULT (fndecl))
- ? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
-
- if (TYPE_MODE (type) == VOIDmode)
- /* There is no return value to worry about. */
- ;
- else if (GET_CODE (loc) == MEM)
- {
- if (GET_CODE (XEXP (loc, 0)) == ADDRESSOF)
- {
- temp = copy_rtx_and_substitute (loc, map, 1);
- subst_constants (&temp, NULL_RTX, map, 1);
- apply_change_group ();
- target = temp;
- }
- else
- {
- 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_operand (structure_value_addr, NULL_RTX);
- temp = force_reg (Pmode, temp);
- /* A virtual register might be invalid in an insn, because
- it can cause trouble in reload. Since we don't have access
- to the expanders at map translation time, make sure we have
- a proper register now.
- If a virtual register is actually valid, cse or combine
- can put it into the mapped insns. */
- if (REGNO (temp) >= FIRST_VIRTUAL_REGISTER
- && REGNO (temp) <= LAST_VIRTUAL_REGISTER)
- temp = copy_to_mode_reg (Pmode, temp);
- 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)))
- {
- SET_CONST_EQUIV_DATA (map, temp, structure_value_addr,
- CONST_AGE_PARM);
- }
- }
- else
- {
- temp = copy_rtx_and_substitute (loc, map, 1);
- subst_constants (&temp, NULL_RTX, map, 0);
- 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)
- {
- /* Don't make BLKmode registers. If this looks like
- a BLKmode object being returned in a register, get
- the mode from that, otherwise abort. */
- if (departing_mode == BLKmode)
- {
- if (REG == GET_CODE (DECL_RTL (DECL_RESULT (fndecl))))
- {
- departing_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
- arriving_mode = departing_mode;
- }
- else
- abort ();
- }
-
- 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 if (GET_CODE (loc) == CONCAT)
- {
- enum machine_mode departing_mode = TYPE_MODE (type);
- enum machine_mode arriving_mode
- = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
-
- if (departing_mode != arriving_mode)
- abort ();
- if (GET_CODE (XEXP (loc, 0)) != REG
- || GET_CODE (XEXP (loc, 1)) != REG)
- abort ();
-
- /* 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 (GET_CODE (target) != CONCAT)
- abort ();
-
- map->reg_map[REGNO (XEXP (loc, 0))] = XEXP (target, 0);
- map->reg_map[REGNO (XEXP (loc, 1))] = XEXP (target, 1);
- }
- else
- abort ();
-
- /* Remap the exception handler data pointer from one to the other. */
- temp = get_exception_pointer (inl_f);
- if (temp)
- map->reg_map[REGNO (temp)] = get_exception_pointer (cfun);
-
- /* Initialize label_map. get_label_from_map will actually make
- the labels. */
- memset ((char *) &map->label_map[min_labelno], 0,
- (max_labelno - min_labelno) * sizeof (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);
- block = integrate_decl_tree (inl_f->original_decl_initial, map);
- BLOCK_ABSTRACT_ORIGIN (block) = DECL_ORIGIN (fndecl);
- inline_function_decl = 0;
-
- /* Make a fresh binding contour that we can easily remove. Do this after
- expanding our arguments so cleanups are properly scoped. */
- expand_start_bindings_and_block (0, block);
-
- /* Sort the block-map so that it will be easy to find remapped
- blocks later. */
- qsort (&VARRAY_TREE (map->block_map, 0),
- map->block_map->elements_used,
- sizeof (tree),
- compare_blocks);
-
- /* 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_varray for
- mark_stores, called via note_stores. */
- global_const_equiv_varray = map->const_equiv_varray;
-
- /* 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 (inl_f->calls_alloca)
- emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);
-
- /* Map pseudos used for initial hard reg values. */
- setup_initial_hard_reg_value_integration (inl_f, map);
-
- /* Now copy the insns one by one. */
- copy_insn_list (insns, map, static_chain_value);
-
- /* Duplicate the EH regions. This will create an offset from the
- region numbers in the function we're inlining to the region
- numbers in the calling function. This must wait until after
- copy_insn_list, as we need the insn map to be complete. */
- eh_region_offset = duplicate_eh_regions (inl_f, map);
-
- /* Now copy the REG_NOTES for those insns. */
- copy_insn_notes (insns, map, eh_region_offset);
-
- /* If the insn sequence required one, emit the return label. */
- if (map->local_return_label)
- emit_label (map->local_return_label);
-
- /* Restore the stack pointer if we saved it above. */
- if (inl_f->calls_alloca)
- emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
-
- if (! cfun->x_whole_function_mode_p)
- /* In statement-at-a-time mode, we just tell the front-end to add
- this block to the list of blocks at this binding level. We
- can't do it the way it's done for function-at-a-time mode the
- superblocks have not been created yet. */
- insert_block (block);
- else
- {
- BLOCK_CHAIN (block)
- = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
- BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block;
- }
-
- /* End the scope containing the copied formal parameter variables
- and copied LABEL_DECLs. We pass NULL_TREE for the variables list
- here so that expand_end_bindings will not check for unused
- variables. That's already been checked for when the inlined
- function was defined. */
- expand_end_bindings (NULL_TREE, 1, 1);
-
- /* Must mark the line number note after inlined functions as a repeat, so
- that the test coverage code can avoid counting the call twice. This
- just tells the code to ignore the immediately following line note, since
- there already exists a copy of this note before the expanded inline call.
- This line number note is still needed for debugging though, so we can't
- delete it. */
- if (flag_test_coverage)
- emit_note (0, NOTE_INSN_REPEATED_LINE_NUMBER);
-
- emit_line_note (input_filename, lineno);
-
- /* If the function returns a BLKmode object in a register, copy it
- out of the temp register into a BLKmode memory object. */
- if (target
- && TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
- && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
- target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
-
- if (structure_value_addr)
- {
- target = gen_rtx_MEM (TYPE_MODE (type),
- memory_address (TYPE_MODE (type),
- structure_value_addr));
- set_mem_attributes (target, type, 1);
- }