@@ -161,6 +161,7 @@ cp_function_decl_explicit_p (tree decl)
{
return (decl
&& FUNCTION_FIRST_USER_PARMTYPE (decl) != void_list_node
+ && DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl))
&& DECL_NONCONVERTING_P (decl));
}
@@ -2951,7 +2951,7 @@ dwarf2out.o : dwarf2out.c $(CONFIG_H) $(
$(LIBFUNCS_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) dwarf2out.h reload.h \
$(GGC_H) $(EXCEPT_H) dwarf2asm.h $(TM_P_H) langhooks.h $(HASHTAB_H) \
gt-dwarf2out.h $(TARGET_H) $(CGRAPH_H) $(MD5_H) $(INPUT_H) $(FUNCTION_H) \
- $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) tree-pretty-print.h
+ $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CFGLAYOUT_H) tree-pretty-print.h
dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(FLAGS_H) $(RTL_H) $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) \
gt-dwarf2asm.h $(DWARF2_H) $(SPLAY_TREE_H) $(TARGET_H)
@@ -3178,7 +3178,7 @@ var-tracking.o : var-tracking.c $(CONFIG
$(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
$(REGS_H) $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(TREE_FLOW_H) \
cselib.h $(TARGET_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h \
- $(RECOG_H) tree-pretty-print.h
+ $(RECOG_H) $(TM_P_H) tree-pretty-print.h
profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) $(FUNCTION_H) $(BASIC_BLOCK_H) \
$(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \
@@ -297,6 +297,7 @@ print_rtx (const_rtx in_rtx)
}
case NOTE_INSN_VAR_LOCATION:
+ case NOTE_INSN_CALL_ARG_LOCATION:
#ifndef GENERATOR_FILE
fputc (' ', outfile);
print_rtx (NOTE_VAR_LOCATION (in_rtx));
@@ -715,6 +715,10 @@ DEF_RTL_EXPR(VAR_LOCATION, "var_location
addressable. */
DEF_RTL_EXPR(DEBUG_IMPLICIT_PTR, "debug_implicit_ptr", "t", RTX_OBJ)
+/* Represents value that argument had on function entry. Should
+ be only used in VAR_LOCATION location expression. */
+DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "e", RTX_OBJ)
+
/* All expressions from this point forward appear only in machine
descriptions. */
#ifdef GENERATOR_FILE
@@ -1999,6 +1999,7 @@ final_scan_insn (rtx insn, FILE *file, i
break;
case NOTE_INSN_VAR_LOCATION:
+ case NOTE_INSN_CALL_ARG_LOCATION:
if (!DECL_IGNORED_P (current_function_decl))
debug_hooks->var_location (insn);
break;
@@ -2670,6 +2671,8 @@ final_scan_insn (rtx insn, FILE *file, i
if (t)
assemble_external (t);
}
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
}
/* Output assembler code from the template. */
@@ -4395,6 +4398,7 @@ rest_of_clean_state (void)
if (final_output
&& (!NOTE_P (insn) ||
(NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
&& NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
&& NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
&& NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE)))
@@ -115,6 +115,7 @@
#include "tree-pretty-print.h"
#include "pointer-set.h"
#include "recog.h"
+#include "tm_p.h"
/* var-tracking.c assumes that tree code with the same value as VALUE rtx code
has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
@@ -408,6 +409,7 @@ static void stack_adjust_offset_pre_post
static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
HOST_WIDE_INT *);
static bool vt_stack_adjustments (void);
+static void note_register_arguments (rtx);
static rtx compute_cfa_pointer (HOST_WIDE_INT);
static hashval_t variable_htab_hash (const void *);
static int variable_htab_eq (const void *, const void *);
@@ -660,11 +662,15 @@ vt_stack_adjustments (void)
for (insn = BB_HEAD (dest);
insn != NEXT_INSN (BB_END (dest));
insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- {
- insn_stack_adjust_offset_pre_post (insn, &pre, &post);
- offset += pre + post;
- }
+ {
+ if (INSN_P (insn))
+ {
+ insn_stack_adjust_offset_pre_post (insn, &pre, &post);
+ offset += pre + post;
+ }
+ if (CALL_P (insn))
+ note_register_arguments (insn);
+ }
VTI (dest)->out.stack_adjust = offset;
@@ -4993,6 +4999,9 @@ log_op_type (rtx x, basic_block bb, rtx
/* All preserved VALUEs. */
static VEC (rtx, heap) *preserved_values;
+/* Registers used in the current function for passing parameters. */
+static HARD_REG_SET argument_reg_set;
+
/* Ensure VAL is preserved and remember it in a vector for vt_emit_notes. */
static void
@@ -5342,6 +5351,15 @@ add_stores (rtx loc, const_rtx expr, voi
{
mo.type = MO_CLOBBER;
mo.u.loc = loc;
+ if (GET_CODE (expr) == SET
+ && SET_DEST (expr) == loc
+ && REGNO (loc) < FIRST_PSEUDO_REGISTER
+ && TEST_HARD_REG_BIT (argument_reg_set, REGNO (loc))
+ && find_use_val (loc, mode, cui))
+ {
+ gcc_checking_assert (type == MO_VAL_SET);
+ mo.u.loc = gen_rtx_SET (VOIDmode, loc, SET_SRC (expr));
+ }
}
else
{
@@ -5558,6 +5576,195 @@ add_stores (rtx loc, const_rtx expr, voi
VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
}
+/* Arguments to the call. */
+static rtx call_arguments;
+
+/* Compute call_arguments. */
+
+static void
+prepare_call_arguments (basic_block bb, rtx insn)
+{
+ rtx link, x;
+ rtx prev, cur, next;
+ rtx call = PATTERN (insn);
+ tree type = NULL_TREE, t;
+ CUMULATIVE_ARGS args_so_far;
+
+ memset (&args_so_far, 0, sizeof (args_so_far));
+ 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))
+ && 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))))
+ {
+ 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)
+ type = NULL;
+ else
+ INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX,
+ SYMBOL_REF_DECL (symbol),
+ list_length (TYPE_ARG_TYPES (type)));
+ }
+ }
+ t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE)
+ {
+ rtx item = NULL_RTX;
+ x = XEXP (XEXP (link, 0), 0);
+ if (REG_P (x))
+ {
+ cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+ if (val && cselib_preserved_value_p (val))
+ item = gen_rtx_CONCAT (GET_MODE (x), x, val->val_rtx);
+ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
+ {
+ enum machine_mode mode = GET_MODE (x);
+
+ while ((mode = GET_MODE_WIDER_MODE (mode)) != VOIDmode
+ && GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
+ {
+ rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0);
+
+ if (reg == NULL_RTX || !REG_P (reg))
+ continue;
+ val = cselib_lookup (reg, mode, 0);
+ if (val && cselib_preserved_value_p (val))
+ {
+ item = gen_rtx_CONCAT (GET_MODE (x), x,
+ lowpart_subreg (GET_MODE (x),
+ val->val_rtx,
+ mode));
+ break;
+ }
+ }
+ }
+ }
+ else if (MEM_P (x))
+ {
+ rtx mem = x;
+ cselib_val *val;
+
+ if (!frame_pointer_needed)
+ {
+ struct adjust_mem_data amd;
+ amd.mem_mode = VOIDmode;
+ amd.stack_adjust = -VTI (bb)->out.stack_adjust;
+ amd.side_effects = NULL_RTX;
+ amd.store = true;
+ mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems,
+ &amd);
+ gcc_assert (amd.side_effects == NULL_RTX);
+ }
+ val = cselib_lookup (mem, GET_MODE (mem), 0);
+ if (val && cselib_preserved_value_p (val))
+ item = gen_rtx_CONCAT (GET_MODE (x), copy_rtx (x), val->val_rtx);
+ }
+ if (item)
+ call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
+ if (t && t != void_list_node)
+ {
+ enum machine_mode mode = TYPE_MODE (TREE_VALUE (t));
+ rtx reg = targetm.calls.function_arg (&args_so_far, mode,
+ TREE_VALUE (t), true);
+ if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t)))
+ && reg
+ && REG_P (reg)
+ && GET_MODE (reg) == mode
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && REG_P (x)
+ && REGNO (x) == REGNO (reg)
+ && GET_MODE (x) == mode
+ && item)
+ {
+ enum machine_mode indmode
+ = TYPE_MODE (TREE_TYPE (TREE_VALUE (t)));
+ rtx mem = gen_rtx_MEM (indmode, x);
+ cselib_val *val = cselib_lookup (mem, indmode, 0);
+ if (val && cselib_preserved_value_p (val))
+ {
+ item = gen_rtx_CONCAT (indmode, mem, val->val_rtx);
+ call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
+ call_arguments);
+ }
+ else
+ {
+ struct elt_loc_list *l;
+ tree initial;
+
+ /* Try harder, when passing address of a constant
+ pool integer it can be easily read back. */
+ val = CSELIB_VAL_PTR (XEXP (item, 1));
+ for (l = val->locs; l; l = l->next)
+ if (GET_CODE (l->loc) == SYMBOL_REF
+ && TREE_CONSTANT_POOL_ADDRESS_P (l->loc)
+ && SYMBOL_REF_DECL (l->loc)
+ && DECL_INITIAL (SYMBOL_REF_DECL (l->loc)))
+ {
+ initial = DECL_INITIAL (SYMBOL_REF_DECL (l->loc));
+ if (host_integerp (initial, 0))
+ {
+ item = GEN_INT (tree_low_cst (initial, 0));
+ item = gen_rtx_CONCAT (indmode, mem, item);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, item,
+ call_arguments);
+ }
+ break;
+ }
+ }
+ }
+ targetm.calls.function_arg_advance (&args_so_far, mode,
+ TREE_VALUE (t), true);
+ t = TREE_CHAIN (t);
+ }
+ }
+
+ /* Reverse call_arguments chain. */
+ prev = NULL_RTX;
+ for (cur = call_arguments; cur; cur = next)
+ {
+ next = XEXP (cur, 1);
+ XEXP (cur, 1) = prev;
+ prev = cur;
+ }
+ call_arguments = prev;
+
+ x = PATTERN (insn);
+ if (GET_CODE (x) == PARALLEL)
+ x = XVECEXP (x, 0, 0);
+ if (GET_CODE (x) == SET)
+ x = SET_SRC (x);
+ if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+ {
+ x = XEXP (XEXP (x, 0), 0);
+ if (GET_CODE (x) != SYMBOL_REF)
+ {
+ cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+ if (val && cselib_preserved_value_p (val))
+ {
+ x = gen_rtx_CONCAT (GET_MODE (x), pc_rtx, val->val_rtx);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+ }
+ }
+ }
+}
+
/* Callback for cselib_record_sets_hook, that records as micro
operations uses and stores in an insn after cselib_record_sets has
analyzed the sets in an insn, but before it modifies the stored
@@ -5627,7 +5834,8 @@ add_with_sets (rtx insn, struct cselib_s
mo.type = MO_CALL;
mo.insn = insn;
- mo.u.loc = NULL_RTX;
+ mo.u.loc = call_arguments;
+ call_arguments = NULL_RTX;
if (dump_file && (dump_flags & TDF_DETAILS))
log_op_type (PATTERN (insn), bb, insn, mo.type, dump_file);
@@ -6943,6 +7151,10 @@ struct expand_loc_callback_data
whose cur_loc has been already recomputed during current
emit_notes_for_changes call. */
bool cur_loc_changed;
+
+ /* True if cur_loc should be ignored and any possible location
+ returned. */
+ bool ignore_cur_loc;
};
/* Callback for cselib_expand_value, that looks for expressions
@@ -6956,6 +7168,7 @@ vt_expand_loc_callback (rtx x, bitmap re
= (struct expand_loc_callback_data *) data;
bool dummy = elcd->dummy;
bool cur_loc_changed = elcd->cur_loc_changed;
+ rtx cur_loc;
decl_or_value dv;
variable var;
location_chain loc;
@@ -7030,7 +7243,7 @@ vt_expand_loc_callback (rtx x, bitmap re
VALUE_RECURSED_INTO (x) = true;
result = NULL;
- if (var->var_part[0].cur_loc)
+ if (var->var_part[0].cur_loc && !elcd->ignore_cur_loc)
{
if (dummy)
{
@@ -7045,12 +7258,16 @@ vt_expand_loc_callback (rtx x, bitmap re
vt_expand_loc_callback, data);
if (result)
set_dv_changed (dv, false);
+ cur_loc = var->var_part[0].cur_loc;
}
- if (!result && dv_changed_p (dv))
+ else
+ cur_loc = NULL_RTX;
+ if (!result && (dv_changed_p (dv) || elcd->ignore_cur_loc))
{
- set_dv_changed (dv, false);
+ if (!elcd->ignore_cur_loc)
+ set_dv_changed (dv, false);
for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
- if (loc->loc == var->var_part[0].cur_loc)
+ if (loc->loc == cur_loc)
continue;
else if (dummy)
{
@@ -7072,7 +7289,8 @@ vt_expand_loc_callback (rtx x, bitmap re
}
if (dummy && (result || var->var_part[0].cur_loc))
var->cur_loc_changed = true;
- var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
+ if (!elcd->ignore_cur_loc)
+ var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
}
if (dummy)
{
@@ -7093,7 +7311,7 @@ vt_expand_loc_callback (rtx x, bitmap re
tables. */
static rtx
-vt_expand_loc (rtx loc, htab_t vars)
+vt_expand_loc (rtx loc, htab_t vars, bool ignore_cur_loc)
{
struct expand_loc_callback_data data;
@@ -7103,6 +7321,7 @@ vt_expand_loc (rtx loc, htab_t vars)
data.vars = vars;
data.dummy = false;
data.cur_loc_changed = false;
+ data.ignore_cur_loc = ignore_cur_loc;
loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
vt_expand_loc_callback, &data);
@@ -7124,6 +7343,7 @@ vt_expand_loc_dummy (rtx loc, htab_t var
data.vars = vars;
data.dummy = true;
data.cur_loc_changed = false;
+ data.ignore_cur_loc = false;
ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
vt_expand_loc_callback, &data);
*pcur_loc_changed = data.cur_loc_changed;
@@ -7201,7 +7421,7 @@ emit_note_insn_var_location (void **varp
complete = false;
continue;
}
- loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars);
+ loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars, false);
if (!loc2)
{
complete = false;
@@ -7231,7 +7451,7 @@ emit_note_insn_var_location (void **varp
&& mode == GET_MODE (var->var_part[j].cur_loc)
&& (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
&& last_limit == var->var_part[j].offset
- && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars))
+ && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars, false))
&& GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
{
rtx new_loc = NULL;
@@ -7692,6 +7912,34 @@ emit_notes_in_bb (basic_block bb, datafl
case MO_CALL:
dataflow_set_clear_at_call (set);
emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
+ {
+ rtx arguments = mo->u.loc, *p = &arguments, note;
+ while (*p)
+ {
+ XEXP (XEXP (*p, 0), 1)
+ = vt_expand_loc (XEXP (XEXP (*p, 0), 1),
+ shared_hash_htab (set->vars), true);
+ /* If expansion is successful, keep it in the list. */
+ if (XEXP (XEXP (*p, 0), 1))
+ p = &XEXP (*p, 1);
+ /* Otherwise, if the following item is data_value for it,
+ drop it too too. */
+ else if (XEXP (*p, 1)
+ && REG_P (XEXP (XEXP (*p, 0), 0))
+ && MEM_P (XEXP (XEXP (XEXP (*p, 1), 0), 0))
+ && REG_P (XEXP (XEXP (XEXP (XEXP (*p, 1), 0), 0),
+ 0))
+ && REGNO (XEXP (XEXP (*p, 0), 0))
+ == REGNO (XEXP (XEXP (XEXP (XEXP (*p, 1), 0),
+ 0), 0)))
+ *p = XEXP (XEXP (*p, 1), 1);
+ /* Just drop this item. */
+ else
+ *p = XEXP (*p, 1);
+ }
+ note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn);
+ NOTE_VAR_LOCATION (note) = arguments;
+ }
break;
case MO_USE:
@@ -8139,7 +8387,8 @@ vt_add_function_parameters (void)
if (offset)
continue;
- val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
+ val = cselib_lookup_from_insn (var_lowpart (mode, incoming), mode,
+ true, get_insns ());
/* ??? Float-typed values in memory are not handled by
cselib. */
@@ -8160,6 +8409,36 @@ vt_add_function_parameters (void)
incoming);
set_variable_part (out, incoming, dv, offset,
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
+ if (dv_is_value_p (dv))
+ {
+ cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
+ struct elt_loc_list *el;
+ el = (struct elt_loc_list *)
+ ggc_alloc_cleared_atomic (sizeof (*el));
+ el->next = val->locs;
+ el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (incoming), incoming);
+ el->setting_insn = get_insns ();
+ val->locs = el;
+ if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
+ {
+ enum machine_mode indmode
+ = TYPE_MODE (TREE_TYPE (TREE_TYPE (parm)));
+ rtx mem = gen_rtx_MEM (indmode, incoming);
+ val = cselib_lookup_from_insn (mem, indmode, true,
+ get_insns ());
+ if (val)
+ {
+ preserve_value (val);
+ el = (struct elt_loc_list *)
+ ggc_alloc_cleared_atomic (sizeof (*el));
+ el->next = val->locs;
+ el->loc = gen_rtx_ENTRY_VALUE (indmode, mem);
+ el->setting_insn = get_insns ();
+ val->locs = el;
+ }
+ }
+ }
}
else if (MEM_P (incoming))
{
@@ -8168,13 +8447,6 @@ vt_add_function_parameters (void)
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
}
}
-
- if (MAY_HAVE_DEBUG_INSNS)
- {
- cselib_preserve_only_values ();
- cselib_reset_table (cselib_get_next_uid ());
- }
-
}
/* Return true if INSN in the prologue initializes hard_frame_pointer_rtx. */
@@ -8202,6 +8474,23 @@ fp_setter (rtx insn)
return false;
}
+/* Gather all registers used for passing arguments to other functions
+ called from the current routine. */
+
+static void
+note_register_arguments (rtx insn)
+{
+ rtx link, x;
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE)
+ {
+ x = XEXP (XEXP (link, 0), 0);
+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ SET_HARD_REG_BIT (argument_reg_set, REGNO (x));
+ }
+}
+
/* Initialize cfa_base_rtx, create a preserved VALUE for it and
ensure it isn't flushed during cselib_reset_table.
Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
@@ -8297,6 +8586,8 @@ vt_initialize (void)
valvar_pool = NULL;
}
+ CLEAR_HARD_REG_SET (argument_reg_set);
+
if (!frame_pointer_needed)
{
rtx reg, elim;
@@ -8343,9 +8634,18 @@ vt_initialize (void)
prologue_bb = single_succ (ENTRY_BLOCK_PTR);
}
}
+ if (frame_pointer_needed)
+ {
+ rtx insn;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (CALL_P (insn))
+ note_register_arguments (insn);
+ }
hard_frame_pointer_adjustment = -1;
+ vt_add_function_parameters ();
+
FOR_EACH_BB (bb)
{
rtx insn;
@@ -8406,6 +8706,8 @@ vt_initialize (void)
adjust_insn (bb, insn);
if (MAY_HAVE_DEBUG_INSNS)
{
+ if (CALL_P (insn))
+ prepare_call_arguments (bb, insn);
cselib_process_insn (insn);
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -8456,7 +8758,6 @@ vt_initialize (void)
hard_frame_pointer_adjustment = -1;
VTI (ENTRY_BLOCK_PTR)->flooded = true;
- vt_add_function_parameters ();
cfa_base_rtx = NULL_RTX;
return true;
}
@@ -2756,9 +2756,7 @@ expand_call (tree exp, rtx target, int i
sibcall_failure = 1;
}
- if (((flags & ECF_CONST)
- || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
- && args[i].stack)
+ if (args[i].stack)
call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_USE (VOIDmode,
args[i].stack),
@@ -3647,6 +3645,8 @@ emit_library_call_value_1 (int retval, r
if (! (reg != 0 && partial == 0))
{
+ rtx use;
+
if (ACCUMULATE_OUTGOING_ARGS)
{
/* If this is being stored into a pre-allocated, fixed-size,
@@ -3717,28 +3717,22 @@ emit_library_call_value_1 (int retval, r
NO_DEFER_POP;
- if ((flags & ECF_CONST)
- || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
- {
- rtx use;
-
- /* Indicate argument access so that alias.c knows that these
- values are live. */
- if (argblock)
- use = plus_constant (argblock,
- argvec[argnum].locate.offset.constant);
- else
- /* When arguments are pushed, trying to tell alias.c where
- exactly this argument is won't work, because the
- auto-increment causes confusion. So we merely indicate
- that we access something with a known mode somewhere on
- the stack. */
- use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
- gen_rtx_SCRATCH (Pmode));
- use = gen_rtx_MEM (argvec[argnum].mode, use);
- use = gen_rtx_USE (VOIDmode, use);
- call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
- }
+ /* Indicate argument access so that alias.c knows that these
+ values are live. */
+ if (argblock)
+ use = plus_constant (argblock,
+ argvec[argnum].locate.offset.constant);
+ else
+ /* When arguments are pushed, trying to tell alias.c where
+ exactly this argument is won't work, because the
+ auto-increment causes confusion. So we merely indicate
+ that we access something with a known mode somewhere on
+ the stack. */
+ use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+ gen_rtx_SCRATCH (Pmode));
+ use = gen_rtx_MEM (argvec[argnum].mode, use);
+ use = gen_rtx_USE (VOIDmode, use);
+ call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
}
}
@@ -27,6 +27,7 @@ extern GTY(()) rtx cfg_layout_function_h
extern void cfg_layout_initialize (unsigned int);
extern void cfg_layout_finalize (void);
+extern tree insn_scope (const_rtx);
extern void reemit_insn_block_notes (void);
extern bool can_copy_bbs_p (basic_block *, unsigned);
extern void copy_bbs (basic_block *, unsigned, basic_block *,
@@ -61,6 +61,9 @@ INSN_NOTE (EH_REGION_END)
/* The location of a variable. */
INSN_NOTE (VAR_LOCATION)
+/* The values passed to callee. */
+INSN_NOTE (CALL_ARG_LOCATION)
+
/* Record the struct for the following basic block. Uses
NOTE_BASIC_BLOCK. FIXME: Redundant with the basic block pointer
now included in every insn. */
@@ -1047,6 +1047,7 @@ adjust_field_rtx_def (type_p t, options_
break;
case NOTE_INSN_VAR_LOCATION:
+ case NOTE_INSN_CALL_ARG_LOCATION:
note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
break;
@@ -92,6 +92,7 @@ along with GCC; see the file COPYING3.
#include "gimple.h"
#include "tree-pass.h"
#include "tree-flow.h"
+#include "cfglayout.h"
static void dwarf2out_source_line (unsigned int, const char *, int, bool);
static rtx last_var_location_insn;
@@ -4700,6 +4701,8 @@ dwarf_stack_op_name (unsigned int op)
return "DW_OP_GNU_encoded_addr";
case DW_OP_GNU_implicit_pointer:
return "DW_OP_GNU_implicit_pointer";
+ case DW_OP_GNU_entry_value:
+ return "DW_OP_GNU_entry_value";
default:
return "OP_<unknown>";
@@ -4806,6 +4809,8 @@ loc_list_plus_const (dw_loc_list_ref lis
#define DWARF_REF_SIZE \
(dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
+static unsigned long size_of_locs (dw_loc_descr_ref);
+
/* Return the size of a location descriptor. */
static unsigned long
@@ -4921,6 +4926,12 @@ size_of_loc_descr (dw_loc_descr_ref loc)
case DW_OP_GNU_implicit_pointer:
size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
break;
+ case DW_OP_GNU_entry_value:
+ {
+ unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc);
+ size += size_of_uleb128 (op_size) + op_size;
+ break;
+ }
default:
break;
}
@@ -4959,6 +4970,8 @@ size_of_locs (dw_loc_descr_ref loc)
static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
static void get_ref_die_offset_label (char *, dw_die_ref);
+static void output_loc_sequence (dw_loc_descr_ref);
+
/* Output location description stack opcode's operands (if any). */
static void
@@ -5188,6 +5201,11 @@ output_loc_operands (dw_loc_descr_ref lo
}
break;
+ case DW_OP_GNU_entry_value:
+ dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL);
+ output_loc_sequence (val1->v.val_loc);
+ break;
+
default:
/* Other codes have no operands. */
break;
@@ -5327,6 +5345,7 @@ output_loc_operands_raw (dw_loc_descr_re
break;
case DW_OP_GNU_implicit_pointer:
+ case DW_OP_GNU_entry_value:
gcc_unreachable ();
break;
@@ -5932,10 +5951,33 @@ struct GTY (()) var_loc_list_def {
};
typedef struct var_loc_list_def var_loc_list;
+/* Call argument location list. */
+struct GTY ((chain_next ("%h.next"))) call_arg_loc_node {
+ rtx GTY (()) call_arg_loc_note;
+ const char * GTY (()) label;
+ tree GTY (()) block;
+ bool tail_call_p;
+ rtx GTY (()) symbol_ref;
+ struct call_arg_loc_node * GTY (()) next;
+};
+
/* Table of decl location linked lists. */
static GTY ((param_is (var_loc_list))) htab_t decl_loc_table;
+/* Head and tail of call_arg_loc chain. */
+static GTY (()) struct call_arg_loc_node *call_arg_locations;
+static struct call_arg_loc_node *call_arg_loc_last;
+
+/* Number of call sites in the current function. */
+static int call_site_count = -1;
+/* Number of tail call sites in the current function. */
+static int tail_call_site_count = -1;
+
+/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
+ DIEs. */
+static VEC (dw_die_ref, heap) *block_map;
+
/* A pointer to the base of a list of references to DIE's that
are uniquely identified by their tag, presence/absence of
children DIE's, and list of attribute/value pairs. */
@@ -6700,6 +6742,10 @@ dwarf_tag_name (unsigned int tag)
return "DW_TAG_GNU_EINCL";
case DW_TAG_GNU_template_template_param:
return "DW_TAG_GNU_template_template_param";
+ case DW_TAG_GNU_call_site:
+ return "DW_TAG_GNU_call_site";
+ case DW_TAG_GNU_call_site_parameter:
+ return "DW_TAG_GNU_call_site_parameter";
default:
return "DW_TAG_<unknown>";
}
@@ -6944,6 +6990,22 @@ dwarf_attr_name (unsigned int attr)
return "DW_AT_GNU_odr_signature";
case DW_AT_GNU_template_name:
return "DW_AT_GNU_template_name";
+ case DW_AT_GNU_call_site_value:
+ return "DW_AT_GNU_call_site_value";
+ case DW_AT_GNU_call_site_data_value:
+ return "DW_AT_GNU_call_site_data_value";
+ case DW_AT_GNU_call_site_target:
+ return "DW_AT_GNU_call_site_target";
+ case DW_AT_GNU_call_site_target_clobbered:
+ return "DW_AT_GNU_call_site_target_clobbered";
+ case DW_AT_GNU_tail_call:
+ return "DW_AT_GNU_tail_call";
+ case DW_AT_GNU_all_tail_call_sites:
+ return "DW_AT_GNU_all_tail_call_sites";
+ case DW_AT_GNU_all_call_sites:
+ return "DW_AT_GNU_all_call_sites";
+ case DW_AT_GNU_all_source_call_sites:
+ return "DW_AT_GNU_all_source_call_sites";
case DW_AT_VMS_rtnbeg_pd_address:
return "DW_AT_VMS_rtnbeg_pd_address";
@@ -13441,11 +13503,18 @@ const_ok_for_output_1 (rtx *rtlp, void *
/* If delegitimize_address couldn't do anything with the UNSPEC, assume
we can't express it in the debug info. */
#ifdef ENABLE_CHECKING
- inform (current_function_decl
- ? DECL_SOURCE_LOCATION (current_function_decl)
- : UNKNOWN_LOCATION,
- "non-delegitimized UNSPEC %d found in variable location",
- XINT (rtl, 1));
+ if (XVECLEN (rtl, 0) != 1
+ || GET_CODE (XVECEXP (rtl, 0, 0)) != SYMBOL_REF
+ || SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0)) == NULL
+ || TREE_CODE (SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0))) != VAR_DECL
+ || !DECL_THREAD_LOCAL_P (SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0))))
+ /* Don't complain about TLS UNSPECs, those are just too hard to
+ delegitimize. */
+ inform (current_function_decl
+ ? DECL_SOURCE_LOCATION (current_function_decl)
+ : UNKNOWN_LOCATION,
+ "non-delegitimized UNSPEC %d found in variable location",
+ XINT (rtl, 1));
#endif
expansion_failed (NULL_TREE, rtl,
"UNSPEC hasn't been delegitimized.\n");
@@ -13695,6 +13764,26 @@ mem_loc_descriptor (rtx rtl, enum machin
"CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
return 0;
+ case ENTRY_VALUE:
+ mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0);
+ mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ if (REG_P (XEXP (rtl, 0)))
+ mem_loc_result->dw_loc_oprnd1.v.val_loc
+ = one_reg_loc_descriptor (dbx_reg_number (XEXP (rtl, 0)),
+ VAR_INIT_STATUS_INITIALIZED);
+ else if (MEM_P (XEXP (rtl, 0)) && REG_P (XEXP (XEXP (rtl, 0), 0)))
+ {
+ dw_loc_descr_ref ref
+ = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+ VAR_INIT_STATUS_INITIALIZED);
+ if (ref == NULL)
+ return NULL;
+ mem_loc_result->dw_loc_oprnd1.v.val_loc = ref;
+ }
+ else
+ gcc_unreachable ();
+ return mem_loc_result;
+
case PRE_MODIFY:
/* Extract the PLUS expression nested inside and fall into
PLUS code below. */
@@ -17531,8 +17620,11 @@ add_linkage_attr (dw_die_ref die, tree d
static void
add_src_coords_attributes (dw_die_ref die, tree decl)
{
- expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+ expanded_location s;
+ if (DECL_SOURCE_LOCATION (decl) == UNKNOWN_LOCATION)
+ return;
+ s = expand_location (DECL_SOURCE_LOCATION (decl));
add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
add_AT_unsigned (die, DW_AT_decl_line, s.line);
}
@@ -18545,6 +18637,8 @@ dwarf2out_abstract_function (tree decl)
tree context;
int was_abstract;
htab_t old_decl_loc_table;
+ int old_call_site_count, old_tail_call_site_count;
+ struct call_arg_loc_node *old_call_arg_locations;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
@@ -18559,6 +18653,12 @@ dwarf2out_abstract_function (tree decl)
get locations in abstract instantces. */
old_decl_loc_table = decl_loc_table;
decl_loc_table = NULL;
+ old_call_arg_locations = call_arg_locations;
+ call_arg_locations = NULL;
+ old_call_site_count = call_site_count;
+ call_site_count = -1;
+ old_tail_call_site_count = tail_call_site_count;
+ tail_call_site_count = -1;
/* Be sure we've emitted the in-class declaration DIE (if any) first, so
we don't get confused by DECL_ABSTRACT. */
@@ -18583,6 +18683,9 @@ dwarf2out_abstract_function (tree decl)
current_function_decl = save_fn;
decl_loc_table = old_decl_loc_table;
+ call_arg_locations = old_call_arg_locations;
+ call_site_count = old_call_site_count;
+ tail_call_site_count = old_tail_call_site_count;
pop_cfun ();
}
@@ -18658,6 +18761,43 @@ premark_types_used_by_global_vars (void)
premark_types_used_by_global_vars_helper, NULL);
}
+/* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
+ for CA_LOC call arg loc node. */
+
+static dw_die_ref
+gen_call_site_die (tree decl, dw_die_ref subr_die,
+ struct call_arg_loc_node *ca_loc)
+{
+ dw_die_ref stmt_die = NULL, die;
+ tree block = ca_loc->block;
+
+ while (block
+ && block != DECL_INITIAL (decl)
+ && TREE_CODE (block) == BLOCK)
+ {
+ if (VEC_length (dw_die_ref, block_map) > BLOCK_NUMBER (block))
+ stmt_die = VEC_index (dw_die_ref, block_map, BLOCK_NUMBER (block));
+ if (stmt_die)
+ break;
+ block = BLOCK_SUPERCONTEXT (block);
+ }
+ if (stmt_die == NULL)
+ stmt_die = subr_die;
+ die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
+ add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
+ if (ca_loc->tail_call_p)
+ add_AT_flag (die, DW_AT_GNU_tail_call, 1);
+ if (ca_loc->symbol_ref)
+ {
+ dw_die_ref tdie = lookup_decl_die (SYMBOL_REF_DECL (ca_loc->symbol_ref));
+ if (tdie)
+ add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
+ else
+ add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
+ }
+ return die;
+}
+
/* Generate a DIE to represent a declared function (either file-scope or
block-local). */
@@ -19036,6 +19176,9 @@ gen_subprogram_die (tree decl, dw_die_re
constructor function. */
if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
{
+ int call_site_note_count = 0;
+ int tail_call_site_note_count = 0;
+
/* Emit a DW_TAG_variable DIE for a named return value. */
if (DECL_NAME (DECL_RESULT (decl)))
gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
@@ -19054,6 +19197,104 @@ gen_subprogram_die (tree decl, dw_die_re
}
}
#endif
+
+ if (call_arg_locations)
+ {
+ struct call_arg_loc_node *ca_loc;
+ for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
+ {
+ dw_die_ref die = NULL;
+ rtx tloc = NULL_RTX;
+ rtx arg, next_arg;
+
+ for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
+ arg; arg = next_arg)
+ {
+ dw_loc_descr_ref reg, val;
+ enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
+ dw_die_ref cdie;
+
+ next_arg = XEXP (arg, 1);
+ if (REG_P (XEXP (XEXP (arg, 0), 0))
+ && next_arg
+ && MEM_P (XEXP (XEXP (next_arg, 0), 0))
+ && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
+ && REGNO (XEXP (XEXP (arg, 0), 0))
+ == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
+ next_arg = XEXP (next_arg, 1);
+ if (mode == VOIDmode)
+ mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
+ if (GET_MODE_CLASS (mode) != MODE_INT
+ || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
+ continue;
+ if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
+ {
+ gcc_assert (ca_loc->symbol_ref == NULL_RTX);
+ tloc = 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);
+ else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
+ reg = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 0),
+ 0), 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ else
+ continue;
+ if (reg == NULL)
+ continue;
+ val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (val == NULL)
+ continue;
+ if (die == NULL)
+ die = gen_call_site_die (decl, subr_die, ca_loc);
+ cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
+ NULL_TREE);
+ add_AT_loc (cdie, DW_AT_location, reg);
+ add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
+ if (next_arg != XEXP (arg, 1))
+ {
+ val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
+ 0), 1), VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (val != NULL)
+ add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
+ }
+ }
+ if (die == NULL
+ && (ca_loc->symbol_ref || tloc))
+ die = gen_call_site_die (decl, subr_die, ca_loc);
+ if (die != NULL && tloc != NULL_RTX)
+ {
+ dw_loc_descr_ref tval
+ = mem_loc_descriptor (tloc, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (tval)
+ add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
+ }
+ if (die != NULL)
+ {
+ call_site_note_count++;
+ if (ca_loc->tail_call_p)
+ tail_call_site_note_count++;
+ }
+ }
+ call_arg_locations = NULL;
+ call_arg_loc_last = NULL;
+ }
+ if (tail_call_site_count >= 0
+ && tail_call_site_count == tail_call_site_note_count)
+ {
+ if (call_site_count >= 0
+ && call_site_count == call_site_note_count)
+ add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
+ else
+ add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
+ }
+ call_site_count = -1;
+ tail_call_site_count = -1;
}
/* Add the calling convention attribute if requested. */
add_calling_convention_attribute (subr_die, decl);
@@ -19442,6 +19683,14 @@ gen_lexical_block_die (tree stmt, dw_die
{
dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+ if (call_arg_locations)
+ {
+ if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt))
+ VEC_safe_grow_cleared (dw_die_ref, heap, block_map,
+ BLOCK_NUMBER (stmt) + 1);
+ VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), stmt_die);
+ }
+
if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
add_high_low_attributes (stmt, stmt_die);
@@ -19472,6 +19721,13 @@ gen_inlined_subroutine_die (tree stmt, d
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
+ if (call_arg_locations)
+ {
+ if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt))
+ VEC_safe_grow_cleared (dw_die_ref, heap, block_map,
+ BLOCK_NUMBER (stmt) + 1);
+ VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), subr_die);
+ }
add_abstract_origin_attribute (subr_die, decl);
if (TREE_ASM_WRITTEN (stmt))
add_high_low_attributes (stmt, subr_die);
@@ -21027,7 +21283,11 @@ static void
dwarf2out_function_decl (tree decl)
{
dwarf2out_decl (decl);
-
+ call_arg_locations = NULL;
+ call_arg_loc_last = NULL;
+ call_site_count = -1;
+ tail_call_site_count = -1;
+ VEC_free (dw_die_ref, heap, block_map);
htab_empty (decl_loc_table);
}
@@ -21381,16 +21641,35 @@ dwarf2out_var_location (rtx loc_note)
static const char *last_postcall_label;
static bool last_in_cold_section_p;
tree decl;
+ bool var_loc_p;
+
+ if (!NOTE_P (loc_note))
+ {
+ if (CALL_P (loc_note))
+ {
+ call_site_count++;
+ if (SIBLING_CALL_P (loc_note))
+ tail_call_site_count++;
+ }
+ return;
+ }
- if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
+ var_loc_p = NOTE_KIND (loc_note) == NOTE_INSN_VAR_LOCATION;
+ if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
return;
next_real = next_real_insn (loc_note);
+
/* If there are no instructions which would be affected by this note,
don't do anything. */
- if (next_real == NULL_RTX && !NOTE_DURING_CALL_P (loc_note))
+ if (var_loc_p
+ && next_real == NULL_RTX
+ && !NOTE_DURING_CALL_P (loc_note))
return;
+ if (next_real == NULL_RTX)
+ next_real = get_last_insn ();
+
/* If there were any real insns between note we processed last time
and this note (or if it is the first note), clear
last_{,postcall_}label so that they are not reused this time. */
@@ -21402,12 +21681,20 @@ dwarf2out_var_location (rtx loc_note)
last_postcall_label = NULL;
}
- decl = NOTE_VAR_LOCATION_DECL (loc_note);
- newloc = add_var_loc_to_decl (decl, loc_note,
- NOTE_DURING_CALL_P (loc_note)
- ? last_postcall_label : last_label);
- if (newloc == NULL)
- return;
+ if (var_loc_p)
+ {
+ decl = NOTE_VAR_LOCATION_DECL (loc_note);
+ newloc = add_var_loc_to_decl (decl, loc_note,
+ NOTE_DURING_CALL_P (loc_note)
+ ? last_postcall_label : last_label);
+ if (newloc == NULL)
+ return;
+ }
+ else
+ {
+ decl = NULL_TREE;
+ newloc = NULL;
+ }
/* If there were no real insns between note we processed last time
and this note, use the label we emitted last time. Otherwise
@@ -21420,7 +21707,43 @@ dwarf2out_var_location (rtx loc_note)
last_label = ggc_strdup (loclabel);
}
- if (!NOTE_DURING_CALL_P (loc_note))
+ if (!var_loc_p)
+ {
+ struct call_arg_loc_node *ca_loc
+ = ggc_alloc_cleared_call_arg_loc_node ();
+ rtx prev = prev_real_insn (loc_note), x;
+ ca_loc->call_arg_loc_note = loc_note;
+ ca_loc->next = NULL;
+ ca_loc->label = last_label;
+ gcc_assert (prev
+ && (CALL_P (prev)
+ || (NONJUMP_INSN_P (prev)
+ && GET_CODE (PATTERN (prev)) == SEQUENCE
+ && CALL_P (XVECEXP (PATTERN (prev), 0, 0)))));
+ if (!CALL_P (prev))
+ prev = XVECEXP (PATTERN (prev), 0, 0);
+ ca_loc->tail_call_p = SIBLING_CALL_P (prev);
+ x = PATTERN (prev);
+ if (GET_CODE (x) == PARALLEL)
+ x = XVECEXP (x, 0, 0);
+ if (GET_CODE (x) == SET)
+ x = SET_SRC (x);
+ if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+ {
+ x = XEXP (XEXP (x, 0), 0);
+ if (GET_CODE (x) == SYMBOL_REF
+ && SYMBOL_REF_DECL (x)
+ && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL)
+ ca_loc->symbol_ref = x;
+ }
+ ca_loc->block = insn_scope (prev);
+ if (call_arg_locations)
+ call_arg_loc_last->next = ca_loc;
+ else
+ call_arg_locations = ca_loc;
+ call_arg_loc_last = ca_loc;
+ }
+ else if (!NOTE_DURING_CALL_P (loc_note))
newloc->label = last_label;
else
{
@@ -21448,6 +21771,8 @@ dwarf2out_begin_function (tree fun)
have_multiple_function_sections = true;
dwarf2out_note_section_used ();
+ call_site_count = 0;
+ tail_call_site_count = 0;
}
/* Output a label to mark the beginning of a source code line entry
@@ -22225,9 +22550,16 @@ resolve_one_addr (rtx *addr, void *data
}
if (GET_CODE (rtl) == SYMBOL_REF
- && SYMBOL_REF_DECL (rtl)
- && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
- return 1;
+ && SYMBOL_REF_DECL (rtl))
+ {
+ if (TREE_CONSTANT_POOL_ADDRESS_P (rtl))
+ {
+ if (!TREE_ASM_WRITTEN (DECL_INITIAL (SYMBOL_REF_DECL (rtl))))
+ return 1;
+ }
+ else if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
+ return 1;
+ }
if (GET_CODE (rtl) == CONST
&& for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
@@ -22319,6 +22651,28 @@ resolve_addr (dw_die_ref die)
remove_AT (die, a->dw_attr);
ix--;
}
+ if (die->die_tag == DW_TAG_GNU_call_site
+ && a->dw_attr == DW_AT_abstract_origin)
+ {
+ tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr);
+ dw_die_ref tdie = lookup_decl_die (tdecl);
+ if (tdie == NULL && DECL_EXTERNAL (tdecl))
+ {
+ force_decl_die (tdecl);
+ tdie = lookup_decl_die (tdecl);
+ }
+ if (tdie)
+ {
+ a->dw_attr_val.val_class = dw_val_class_die_ref;
+ a->dw_attr_val.v.val_die_ref.die = tdie;
+ a->dw_attr_val.v.val_die_ref.external = 0;
+ }
+ else
+ {
+ remove_AT (die, a->dw_attr);
+ ix--;
+ }
+ }
break;
default:
break;
@@ -54,7 +54,6 @@ static void change_scope (rtx, tree, tre
void verify_insn_chain (void);
static void fixup_fallthru_exit_predecessor (void);
-static tree insn_scope (const_rtx);
rtx
unlink_insn_chain (rtx first, rtx last)
@@ -499,7 +498,7 @@ locator_scope (int loc)
}
/* Return lexical scope block insn belongs to. */
-static tree
+tree
insn_scope (const_rtx insn)
{
return locator_scope (INSN_LOCATOR (insn));
@@ -228,6 +228,8 @@ enum dwarf_tag
are properly part of DWARF 5. */
DW_TAG_GNU_template_parameter_pack = 0x4107,
DW_TAG_GNU_formal_parameter_pack = 0x4108,
+ DW_TAG_GNU_call_site = 0x4109,
+ DW_TAG_GNU_call_site_parameter = 0x410a,
/* Extensions for UPC. See: http://upc.gwu.edu/~upc. */
DW_TAG_upc_shared_type = 0x8765,
DW_TAG_upc_strict_type = 0x8766,
@@ -438,6 +440,14 @@ enum dwarf_attribute
/* Template template argument name.
See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */
DW_AT_GNU_template_name = 0x2110,
+ DW_AT_GNU_call_site_value = 0x2111,
+ DW_AT_GNU_call_site_data_value = 0x2112,
+ DW_AT_GNU_call_site_target = 0x2113,
+ DW_AT_GNU_call_site_target_clobbered = 0x2114,
+ DW_AT_GNU_tail_call = 0x2115,
+ DW_AT_GNU_all_tail_call_sites = 0x2116,
+ DW_AT_GNU_all_call_sites = 0x2117,
+ DW_AT_GNU_all_source_call_sites = 0x2118,
/* VMS extensions. */
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
/* GNAT extensions. */
@@ -623,6 +633,7 @@ enum dwarf_location_atom
DW_OP_GNU_uninit = 0xf0,
DW_OP_GNU_encoded_addr = 0xf1,
DW_OP_GNU_implicit_pointer = 0xf2,
+ DW_OP_GNU_entry_value = 0xf3,
/* HP extensions. */
DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */
DW_OP_HP_is_value = 0xe1,