* calls.c (emit_call_1): Set MEM_EXPR on call's MEM.
* var-tracking.c (prepare_call_arguments): Use MEM_EXPR on
call's MEM. Handle functions returning aggregate through a hidden
first pointer. For virtual calls add clobbered pc to call arguments
chain.
* dwarf2out.c (gen_subprogram_die): Emit
DW_AT_GNU_call_site_target_clobbered if DW_AT_GNU_call_site_target
can't be emitted.
From-SVN: r171036
2011-03-16 Jakub Jelinek <jakub@redhat.com>
+ * calls.c (emit_call_1): Set MEM_EXPR on call's MEM.
+ * var-tracking.c (prepare_call_arguments): Use MEM_EXPR on
+ call's MEM. Handle functions returning aggregate through a hidden
+ first pointer. For virtual calls add clobbered pc to call arguments
+ chain.
+ * dwarf2out.c (gen_subprogram_die): Emit
+ DW_AT_GNU_call_site_target_clobbered if DW_AT_GNU_call_site_target
+ can't be emitted.
+
PR debug/45882
* rtl.def (ENTRY_VALUE): Change format from "e" to "0".
* rtl.h (ENTRY_VALUE_EXP): Define.
CUMULATIVE_ARGS *args_so_far ATTRIBUTE_UNUSED)
{
rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
- rtx call_insn;
+ rtx call_insn, call, funmem;
int already_popped = 0;
HOST_WIDE_INT n_popped
= targetm.calls.return_pops_args (fndecl, funtype, stack_size);
if (GET_CODE (funexp) != SYMBOL_REF)
funexp = memory_address (FUNCTION_MODE, funexp);
+ funmem = gen_rtx_MEM (FUNCTION_MODE, funexp);
+ if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL)
+ set_mem_expr (funmem, fndecl);
+ else if (fntree)
+ set_mem_expr (funmem, build_fold_indirect_ref (CALL_EXPR_FN (fntree)));
+
#if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
if ((ecf_flags & ECF_SIBCALL)
&& HAVE_sibcall_pop && HAVE_sibcall_value_pop
if possible, for the sake of frame pointer elimination. */
if (valreg)
- pat = GEN_SIBCALL_VALUE_POP (valreg,
- gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg,
- n_pop);
+ pat = GEN_SIBCALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
+ next_arg_reg, n_pop);
else
- pat = GEN_SIBCALL_POP (gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg, n_pop);
+ pat = GEN_SIBCALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
+ n_pop);
emit_call_insn (pat);
already_popped = 1;
if possible, for the sake of frame pointer elimination. */
if (valreg)
- pat = GEN_CALL_VALUE_POP (valreg,
- gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg, n_pop);
+ pat = GEN_CALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
+ next_arg_reg, n_pop);
else
- pat = GEN_CALL_POP (gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg, n_pop);
+ pat = GEN_CALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
+ n_pop);
emit_call_insn (pat);
already_popped = 1;
&& HAVE_sibcall && HAVE_sibcall_value)
{
if (valreg)
- emit_call_insn (GEN_SIBCALL_VALUE (valreg,
- gen_rtx_MEM (FUNCTION_MODE, funexp),
+ emit_call_insn (GEN_SIBCALL_VALUE (valreg, funmem,
rounded_stack_size_rtx,
next_arg_reg, NULL_RTX));
else
- emit_call_insn (GEN_SIBCALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg,
+ emit_call_insn (GEN_SIBCALL (funmem, rounded_stack_size_rtx,
+ next_arg_reg,
GEN_INT (struct_value_size)));
}
else
if (HAVE_call && HAVE_call_value)
{
if (valreg)
- emit_call_insn (GEN_CALL_VALUE (valreg,
- gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg,
- NULL_RTX));
+ emit_call_insn (GEN_CALL_VALUE (valreg, funmem, rounded_stack_size_rtx,
+ next_arg_reg, NULL_RTX));
else
- emit_call_insn (GEN_CALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
- rounded_stack_size_rtx, next_arg_reg,
+ emit_call_insn (GEN_CALL (funmem, rounded_stack_size_rtx, next_arg_reg,
GEN_INT (struct_value_size)));
}
else
/* Find the call we just emitted. */
call_insn = last_call_insn ();
+ /* Some target create a fresh MEM instead of reusing the one provided
+ above. Set its MEM_EXPR. */
+ call = PATTERN (call_insn);
+ if (GET_CODE (call) == PARALLEL)
+ call = XVECEXP (call, 0, 0);
+ if (GET_CODE (call) == SET)
+ call = SET_SRC (call);
+ if (GET_CODE (call) == CALL
+ && MEM_P (XEXP (call, 0))
+ && MEM_EXPR (XEXP (call, 0)) == NULL_TREE
+ && MEM_EXPR (funmem) != NULL_TREE)
+ set_mem_expr (XEXP (call, 0), MEM_EXPR (funmem));
+
/* Put the register usage information there. */
add_function_usage_to (call_insn, call_fusage);
for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
{
dw_die_ref die = NULL;
- rtx tloc = NULL_RTX;
+ rtx tloc = NULL_RTX, tlocc = NULL_RTX;
rtx arg, next_arg;
for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
tloc = XEXP (XEXP (arg, 0), 1);
continue;
}
+ else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
+ && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
+ {
+ gcc_assert (ca_loc->symbol_ref == NULL_RTX);
+ tlocc = XEXP (XEXP (arg, 0), 1);
+ continue;
+ }
if (REG_P (XEXP (XEXP (arg, 0), 0)))
reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
VAR_INIT_STATUS_INITIALIZED);
if (die == NULL
&& (ca_loc->symbol_ref || tloc))
die = gen_call_site_die (decl, subr_die, ca_loc);
- if (die != NULL && tloc != NULL_RTX)
+ if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
{
- dw_loc_descr_ref tval
- = mem_loc_descriptor (tloc, VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref tval = NULL;
+
+ if (tloc != NULL_RTX)
+ tval = mem_loc_descriptor (tloc, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
if (tval)
add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
+ else if (tlocc != NULL_RTX)
+ {
+ tval = mem_loc_descriptor (tlocc, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (tval)
+ add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
+ tval);
+ }
}
if (die != NULL)
{
rtx link, x;
rtx prev, cur, next;
rtx call = PATTERN (insn);
- tree type = NULL_TREE, t;
+ rtx this_arg = NULL_RTX;
+ tree type = NULL_TREE, t, fndecl = NULL_TREE;
+ tree obj_type_ref = NULL_TREE;
CUMULATIVE_ARGS args_so_far;
memset (&args_so_far, 0, sizeof (args_so_far));
call = XVECEXP (call, 0, 0);
if (GET_CODE (call) == SET)
call = SET_SRC (call);
- if (GET_CODE (call) == CALL
- && MEM_P (XEXP (call, 0))
- && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
- {
- rtx symbol = XEXP (XEXP (call, 0), 0);
- if (SYMBOL_REF_DECL (symbol)
- && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL
- && TYPE_ARG_TYPES (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
+ if (GET_CODE (call) == CALL && MEM_P (XEXP (call, 0)))
+ {
+ if (GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+ {
+ rtx symbol = XEXP (XEXP (call, 0), 0);
+ if (SYMBOL_REF_DECL (symbol))
+ fndecl = SYMBOL_REF_DECL (symbol);
+ }
+ if (fndecl == NULL_TREE)
+ fndecl = MEM_EXPR (XEXP (call, 0));
+ if (fndecl
+ && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
+ fndecl = NULL_TREE;
+ if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+ type = TREE_TYPE (fndecl);
+ if (fndecl && TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ if (TREE_CODE (fndecl) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (fndecl, 0)) == OBJ_TYPE_REF)
+ obj_type_ref = TREE_OPERAND (fndecl, 0);
+ fndecl = NULL_TREE;
+ }
+ if (type)
{
- type = TREE_TYPE (SYMBOL_REF_DECL (symbol));
for (t = TYPE_ARG_TYPES (type); t && t != void_list_node;
t = TREE_CHAIN (t))
if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t))))
break;
- if (t == NULL || t == void_list_node)
+ if ((t == NULL || t == void_list_node) && obj_type_ref == NULL_TREE)
type = NULL;
else
- INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX,
- SYMBOL_REF_DECL (symbol),
- list_length (TYPE_ARG_TYPES (type)));
+ {
+ int nargs = list_length (TYPE_ARG_TYPES (type));
+ link = CALL_INSN_FUNCTION_USAGE (insn);
+#ifndef PCC_STATIC_STRUCT_RETURN
+ if (aggregate_value_p (TREE_TYPE (type), type)
+ && targetm.calls.struct_value_rtx (type, 0) == 0)
+ {
+ tree struct_addr = build_pointer_type (TREE_TYPE (type));
+ enum machine_mode mode = TYPE_MODE (struct_addr);
+ rtx reg;
+ INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX, fndecl,
+ nargs + 1);
+ reg = targetm.calls.function_arg (&args_so_far, mode,
+ struct_addr, true);
+ targetm.calls.function_arg_advance (&args_so_far, mode,
+ struct_addr, true);
+ if (reg == NULL_RTX)
+ {
+ for (; link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE
+ && MEM_P (XEXP (XEXP (link, 0), 0)))
+ {
+ link = XEXP (link, 1);
+ break;
+ }
+ }
+ }
+#endif
+ else
+ INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX, fndecl,
+ nargs);
+ if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
+ {
+ enum machine_mode mode;
+ t = TYPE_ARG_TYPES (type);
+ mode = TYPE_MODE (TREE_VALUE (t));
+ this_arg = targetm.calls.function_arg (&args_so_far, mode,
+ TREE_VALUE (t), true);
+ if (this_arg && !REG_P (this_arg))
+ this_arg = NULL_RTX;
+ else if (this_arg == NULL_RTX)
+ {
+ for (; link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE
+ && MEM_P (XEXP (XEXP (link, 0), 0)))
+ {
+ this_arg = XEXP (XEXP (link, 0), 0);
+ break;
+ }
+ }
+ }
+ }
}
}
t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
}
}
}
+ if (this_arg)
+ {
+ enum machine_mode mode
+ = TYPE_MODE (TREE_TYPE (OBJ_TYPE_REF_EXPR (obj_type_ref)));
+ rtx clobbered = gen_rtx_MEM (mode, this_arg);
+ HOST_WIDE_INT token
+ = tree_low_cst (OBJ_TYPE_REF_TOKEN (obj_type_ref), 0);
+ if (token)
+ clobbered = plus_constant (clobbered, token * GET_MODE_SIZE (mode));
+ clobbered = gen_rtx_MEM (mode, clobbered);
+ x = gen_rtx_CONCAT (mode, gen_rtx_CLOBBER (VOIDmode, pc_rtx), clobbered);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+ }
}
/* Callback for cselib_record_sets_hook, that records as micro