#include "timevar.h"
#include "vecprim.h"
+/* So we can assign to cfun in this file. */
+#undef cfun
+
#ifndef LOCAL_ALIGNMENT
#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
#endif
struct function *p;
if (cfun == 0)
- allocate_struct_function (NULL);
+ allocate_struct_function (NULL, false);
p = cfun;
p->outer = outer_function_chain;
}
/* Process all subblocks. */
- for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
+ for (t = BLOCK_SUBBLOCKS (let); t; t = BLOCK_CHAIN (t))
instantiate_decls_1 (t);
}
#endif
)
{
- rtx reg = gen_rtx_REG (mode, REGNO (entry_parm));
+ rtx reg;
+
+ /* We are really truncating a word_mode value containing
+ SIZE bytes into a value of mode MODE. If such an
+ operation requires no actual instructions, we can refer
+ to the value directly in mode MODE, otherwise we must
+ start with the register in word_mode and explicitly
+ convert it. */
+ if (TRULY_NOOP_TRUNCATION (size * BITS_PER_UNIT, BITS_PER_WORD))
+ reg = gen_rtx_REG (mode, REGNO (entry_parm));
+ else
+ {
+ reg = gen_rtx_REG (word_mode, REGNO (entry_parm));
+ reg = convert_to_mode (mode, copy_to_reg (reg), 1);
+ }
emit_move_insn (change_address (mem, mode, 0), reg);
}
imag = gen_lowpart_SUBREG (inner, imag);
}
tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
- set_decl_incoming_rtl (parm, tmp);
+ set_decl_incoming_rtl (parm, tmp, false);
fnargs = TREE_CHAIN (fnargs);
}
else
{
SET_DECL_RTL (parm, DECL_RTL (fnargs));
- set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs));
+ set_decl_incoming_rtl (parm, DECL_INCOMING_RTL (fnargs), false);
/* Set MEM_EXPR to the original decl, i.e. to PARM,
instead of the copy of decl, i.e. FNARGS. */
}
/* Record permanently how this parm was passed. */
- set_decl_incoming_rtl (parm, data.entry_parm);
+ set_decl_incoming_rtl (parm, data.entry_parm, data.passed_pointer);
/* Update info on where next arg arrives in registers. */
FUNCTION_ARG_ADVANCE (all.args_so_far, data.promoted_mode,
" %<longjmp%> or %<vfork%>", decl);
}
- for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
+ for (sub = BLOCK_SUBBLOCKS (block); sub; sub = BLOCK_CHAIN (sub))
setjmp_vars_warning (setjmp_crosses, sub);
}
static VEC(function_p,heap) *cfun_stack;
+/* We save the value of in_system_header here when pushing the first
+ function on the cfun stack, and we restore it from here when
+ popping the last function. */
+
+static bool saved_in_system_header;
+
/* Push the current cfun onto the stack, and set cfun to new_cfun. */
void
push_cfun (struct function *new_cfun)
{
+ if (cfun == NULL)
+ saved_in_system_header = in_system_header;
VEC_safe_push (function_p, heap, cfun_stack, cfun);
+ if (new_cfun)
+ in_system_header = DECL_IN_SYSTEM_HEADER (new_cfun->decl);
set_cfun (new_cfun);
}
void
pop_cfun (void)
{
- set_cfun (VEC_pop (function_p, cfun_stack));
+ struct function *new_cfun = VEC_pop (function_p, cfun_stack);
+ in_system_header = ((new_cfun == NULL) ? saved_in_system_header
+ : DECL_IN_SYSTEM_HEADER (new_cfun->decl));
+ set_cfun (new_cfun);
}
/* Return value of funcdef and increase it. */
directly into cfun and invoke the back end hook explicitly at the
very end, rather than initializing a temporary and calling set_cfun
on it.
-*/
+
+ ABSTRACT_P is true if this is a function that will never be seen by
+ the middle-end. Such functions are front-end concepts (like C++
+ function templates) that do not correspond directly to functions
+ placed in object files. */
void
-allocate_struct_function (tree fndecl)
+allocate_struct_function (tree fndecl, bool abstract_p)
{
tree result;
tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE;
cfun->decl = fndecl;
result = DECL_RESULT (fndecl);
- if (aggregate_value_p (result, fndecl))
+ if (!abstract_p && aggregate_value_p (result, fndecl))
{
#ifdef PCC_STATIC_STRUCT_RETURN
current_function_returns_pcc_struct = 1;
void
push_struct_function (tree fndecl)
{
+ if (cfun == NULL)
+ saved_in_system_header = in_system_header;
VEC_safe_push (function_p, heap, cfun_stack, cfun);
- allocate_struct_function (fndecl);
+ if (fndecl)
+ in_system_header = DECL_IN_SYSTEM_HEADER (fndecl);
+ allocate_struct_function (fndecl, false);
}
/* Reset cfun, and other non-struct-function variables to defaults as
if (subr && DECL_STRUCT_FUNCTION (subr))
set_cfun (DECL_STRUCT_FUNCTION (subr));
else
- allocate_struct_function (subr);
+ allocate_struct_function (subr, false);
prepare_function_start ();
/* Warn if this value is an aggregate type,
tree parm = cfun->static_chain_decl;
rtx local = gen_reg_rtx (Pmode);
- set_decl_incoming_rtl (parm, static_chain_incoming_rtx);
+ set_decl_incoming_rtl (parm, static_chain_incoming_rtx, false);
SET_DECL_RTL (parm, local);
mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
rtx input, output, insns;
const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
char *end;
- int match;
+ int match, j;
match = strtoul (constraint, &end, 10);
if (end == constraint)
gcc_assert (match < noutputs);
output = SET_DEST (p_sets[match]);
input = RTVEC_ELT (inputs, i);
- if (rtx_equal_p (output, input)
+ /* Only do the transformation for pseudos. */
+ if (! REG_P (output)
+ || rtx_equal_p (output, input)
|| (GET_MODE (input) != VOIDmode
&& GET_MODE (input) != GET_MODE (output)))
continue;
+ /* We can't do anything if the output is also used as input,
+ as we're going to overwrite it. */
+ for (j = 0; j < ninputs; j++)
+ if (reg_overlap_mentioned_p (output, RTVEC_ELT (inputs, j)))
+ break;
+ if (j != ninputs)
+ continue;
+
start_sequence ();
- emit_move_insn (copy_rtx (output), input);
- RTVEC_ELT (inputs, i) = copy_rtx (output);
+ emit_move_insn (output, input);
insns = get_insns ();
end_sequence ();
-
emit_insn_before (insns, insn);
+
+ /* Now replace all mentions of the input with output. We can't
+ just replace the occurence in inputs[i], as the register might
+ also be used in some other input (or even in an address of an
+ output), which would mean possibly increasing the number of
+ inputs by one (namely 'output' in addition), which might pose
+ a too complicated problem for reload to solve. E.g. this situation:
+
+ asm ("" : "=r" (output), "=m" (input) : "0" (input))
+
+ Here 'input' is used in two occurrences as input (once for the
+ input operand, once for the address in the second output operand).
+ If we would replace only the occurence of the input operand (to
+ make the matching) we would be left with this:
+
+ output = input
+ asm ("" : "=r" (output), "=m" (input) : "0" (output))
+
+ Now we suddenly have two different input values (containing the same
+ value, but different pseudos) where we formerly had only one.
+ With more complicated asms this might lead to reload failures
+ which wouldn't have happen without this pass. So, iterate over
+ all operands and replace all occurrences of the register used. */
+ for (j = 0; j < noutputs; j++)
+ if (!rtx_equal_p (SET_DEST (p_sets[j]), input)
+ && reg_overlap_mentioned_p (input, SET_DEST (p_sets[j])))
+ SET_DEST (p_sets[j]) = replace_rtx (SET_DEST (p_sets[j]),
+ input, output);
+ for (j = 0; j < ninputs; j++)
+ if (reg_overlap_mentioned_p (input, RTVEC_ELT (inputs, j)))
+ RTVEC_ELT (inputs, j) = replace_rtx (RTVEC_ELT (inputs, j),
+ input, output);
+
changed = true;
}