/* Procedure integration for GNU CC.
- Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1991, 1993 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
static tree copy_decl_tree ();
static tree copy_decl_list ();
-/* Return the constant equivalent of a given rtx, or 0 if none. */
-static rtx const_equiv ();
-
static void integrate_parm_decls ();
static void integrate_decl_tree ();
static void subst_constants ();
-static rtx fold_out_const_cc0 ();
\f
/* Zero if the current function (whose FUNCTION_DECL is FNDECL)
is safe and reasonable to integrate into other functions.
if (current_function_contains_functions)
return "function with nested functions cannot be inline";
- /* This restriction may be eliminated sometime soon. But for now, don't
- worry about remapping the static chain. */
- if (current_function_needs_context)
- return "nested function cannot be inline";
-
/* If its not even close, don't even look. */
if (!DECL_INLINE (fndecl) && get_max_uid () > 3 * max_insns)
return "function too large to be inline";
(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)
+ && 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
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;
/* Where parameter is located in the function. */
rtx copy;
- rtx note = emit_note (DECL_SOURCE_FILE (formal),
- DECL_SOURCE_LINE (formal));
- if (note)
- RTX_INTEGRATED_P (note) = 1;
+ /* Make sure this formal has some correspondence in the users code
+ * before emitting any line notes for it. */
+ if (DECL_SOURCE_LINE (formal))
+ {
+ rtx note = emit_note (DECL_SOURCE_FILE (formal),
+ DECL_SOURCE_LINE (formal));
+ if (note)
+ RTX_INTEGRATED_P (note) = 1;
+ }
arg_trees[i] = arg;
loc = RTVEC_ELT (arg_vector, i);
arg_vals[i] = XEXP (stack_slot, 0);
}
else if (GET_CODE (loc) != MEM)
- /* 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_to_mode (GET_MODE (loc),
- expand_expr (arg, NULL_RTX, mode,
- EXPAND_SUM),
- TREE_UNSIGNED (TREE_TYPE (formal)));
+ {
+ 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_to_mode (GET_MODE (loc),
+ 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;
&& (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))))
+ && 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]);
}
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,
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);
+
/* 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
{
/* 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 (GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
+ constant equivalence.
+
+ If LOC is REG_USERVAR_P, the usual case, COPY must also have
+ that flag set if it is a register. */
+
+ if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
+ || (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
+ && ! REG_USERVAR_P (copy)))
{
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))
{
map->const_equiv_map[REGNO (temp)] = copy;
else
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
+ && GET_CODE (pattern) == SET
+ && rtx_equal_p (SET_SRC (pattern),
+ static_chain_incoming_rtx))
+ {
+ rtx newdest = copy_rtx_and_substitute (SET_DEST (pattern), map);
+
+ copy = emit_insn (gen_rtx (SET, VOIDmode, newdest,
+ static_chain_value));
+
+ static_chain_value = 0;
+ }
else
copy = emit_insn (copy_rtx_and_substitute (pattern, map));
/* REG_NOTES will be copied later. */
map->insn_map[INSN_UID (insn)] = copy;
}
- /* Now copy the REG_NOTES. */
+ /* 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 (map->insn_map[INSN_UID (insn)])
- = copy_rtx_and_substitute (REG_NOTES (insn), map);
+ && 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);
emit_line_note (input_filename, lineno);
if (structure_value_addr)
- return gen_rtx (MEM, TYPE_MODE (type),
- memory_address (TYPE_MODE (type), 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;
}
\f
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 to require some more work. */
+ /* DECL_INCOMING_RTL (decl) = ?; */
/* These args would always appear unused, if not for this. */
TREE_USED (decl) = 1;
/* Prevent warning for shadowing with these. */
reach here, so return the register unchanged. */
return orig;
else if (mode != GET_MODE (map->inline_target))
- return gen_rtx (SUBREG, mode, map->inline_target, 0);
+ return gen_lowpart (mode, map->inline_target);
else
return map->inline_target;
}
case USE:
case CLOBBER:
/* USE and CLOBBER are ordinary, but we convert (use (subreg foo))
- to (use foo). */
+ to (use foo) if the original insn didn't have a subreg.
+ Removing the subreg distorts the VAX movstrhi pattern
+ by changing the mode of an operand. */
copy = copy_rtx_and_substitute (XEXP (orig, 0), map);
- if (GET_CODE (copy) == SUBREG)
+ if (GET_CODE (copy) == SUBREG && GET_CODE (XEXP (orig, 0)) != SUBREG)
copy = SUBREG_REG (copy);
return gen_rtx (code, VOIDmode, copy);
XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map);
MEM_IN_STRUCT_P (copy) = MEM_IN_STRUCT_P (orig);
MEM_VOLATILE_P (copy) = MEM_VOLATILE_P (orig);
- RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
+
+ /* If doing function inlining, this MEM might not be const in the
+ function that it is being inlined into, and thus may not be
+ unchanging after function inlining. Constant pool references are
+ handled elsewhere, so this doesn't lose RTX_UNCHANGING_P bits
+ for them. */
+ if (! map->integrating)
+ RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
+
return copy;
}
&& GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
<= GET_MODE_SIZE (GET_MODE (dest)))
- && (tem = gen_lowpart_if_possible (GET_MODE (dest), src)))
+ && (tem = gen_lowpart_if_possible (GET_MODE (SUBREG_REG (dest)),
+ src)))
src = tem, dest = SUBREG_REG (dest);
/* If storing a recognizable value save it for later recording. */
rtx dest;
rtx x;
{
- if (GET_CODE (dest) == SUBREG)
- dest = SUBREG_REG (dest);
+ int regno = -1;
+ enum machine_mode mode;
+
+ /* DEST is always the innermost thing set, except in the case of
+ SUBREGs of hard registers. */
if (GET_CODE (dest) == REG)
- global_const_equiv_map[REGNO (dest)] = 0;
+ regno = REGNO (dest), mode = GET_MODE (dest);
+ else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
+ {
+ regno = REGNO (SUBREG_REG (dest)) + SUBREG_WORD (dest);
+ mode = GET_MODE (SUBREG_REG (dest));
+ }
+
+ if (regno >= 0)
+ {
+ int last_reg = (regno >= FIRST_PSEUDO_REGISTER ? regno
+ : regno + HARD_REGNO_NREGS (regno, mode) - 1);
+ int i;
+
+ for (i = regno; i <= last_reg; i++)
+ global_const_equiv_map[i] = 0;
+ }
}
\f
/* If any CONST expressions with RTX_INTEGRATED_P are present in the rtx
rtx head = DECL_SAVED_INSNS (fndecl);
rtx last;
- temporary_allocation ();
-
current_function_decl = fndecl;
/* This call is only used to initialize global variables. */
rest_of_compilation (fndecl);
current_function_decl = 0;
-
- permanent_allocation ();
}