[PATCH] Updated DW_OP_GNU_entry_value/DW_TAG_GNU_call_site patch
Richard Guenther
richard.guenther@gmail.com
Mon Dec 27 08:11:00 GMT 2010
On Thu, Dec 23, 2010 at 9:53 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> Here is the entry value/call site patch updated to current trunk.
> The only important change is the integrate.c change, which prevents ICE when
> BLOCK_VARS of some inline fn contain DECL_EXTERNAL FUNCTION_DECLs and
> dwarf2out sets even for the externals DECL_ABSTRACT_ORIGIN to self, yet
> they are not DECL_ABSTRACT and thus force_decl_die on them crashes.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux.
Hopefully not for stage3?
Richard.
> 2010-12-23 Jakub Jelinek <jakub@redhat.com>
>
> * final.c (final_scan_insn): Handle NOTE_INSN_CALL_ARG_LOCATION.
> Call var_location debug hook even on CALL_INSNs.
> (rest_of_clean_state): Don't print NOTE_INSN_CALL_ARG_LOCATION.
> * rtl.def (ENTRY_VALUE): New.
> * dwarf2out.c: Include cfglayout.h.
> (dwarf_stack_op_name, size_of_loc_descr, output_loc_operands,
> output_loc_operands_raw): Handle DW_OP_GNU_entry_value.
> (struct call_arg_loc_node): New type.
> (call_arg_locations, call_arg_loc_last, block_map, call_site_count,
> tail_call_site_count): New variables.
> (dwarf_tag_name): Handle DW_TAG_GNU_call_site and
> DW_TAG_GNU_call_site_parameter.
> (dwarf_attr_name): Handle DW_AT_GNU_call_site_value,
> DW_AT_GNU_call_site_data_value, DW_AT_GNU_call_site_target,
> DW_AT_GNU_call_site_target_clobbered, DW_AT_GNU_tail_call,
> DW_AT_GNU_all_tail_call_sites, DW_AT_GNU_all_call_sites
> and DW_AT_GNU_all_source_call_sites.
> (mem_loc_descriptor): Handle ENTRY_VALUE.
> (add_src_coords_attributes): Don't add enything if
> DECL_SOURCE_LOCATION is UNKNOWN_LOCATION.
> (dwarf2out_abstract_function): Save and clear call_arg_location,
> call_site_count and tail_call_site_count around dwarf2out_decl call.
> (gen_call_site_die): New function.
> (gen_subprogram_die): Emit DW_TAG_GNU_call_site DIEs for call sites.
> (gen_lexical_block_die, gen_inlined_subroutine_die): Update block_map.
> (dwarf2out_function_decl): Clear call_arg_locations,
> call_arg_loc_last, set call_site_count and tail_call_site_count
> to -1 and free block_map.
> (dwarf2out_var_location): Handle NOTE_INSN_CALL_ARG_LOCATION and
> CALL_INSNs. Add NOTE_DURING_CALL_P var location notes even when not
> followed by any real instructions.
> (dwarf2out_begin_function): Set call_site_count and
> tail_call_site_count to 0.
> (resolve_addr): If DW_AT_abstract_origin of DW_TAG_GNU_call_site
> is dw_val_class_addr, attempt to look it up again, for DECL_EXTERNAL
> attempt to force a DIE for it and worst case remove the attribute.
> (resolve_one_addr): For TREE_CONSTANT_POOL_ADDRESS_P SYMBOL_REFs
> check TREE_ASM_WRITTEN of DECL_INITIAL of the decl instead of
> the decl itself.
> * var-tracking.c: Include tm_p.h.
> (vt_stack_adjustments): For calls call note_register_arguments.
> (argument_reg_set): New variable.
> (add_stores): For MO_VAL_SET of non-tracked regs from argument_reg_set
> ensure the VALUE is resolved.
> (call_arguments): New variable.
> (prepare_call_arguments): New function.
> (add_with_sets): For MO_CALL set u.loc from call_arguments and clear it.
> (struct expand_loc_callback_data): Add ignore_cur_loc field.
> (vt_expand_loc_callback): If ignore_cur_loc, don't look at cur_loc and
> always use the best expression.
> (vt_expand_loc): Add ignore_cur_loc argument.
> (vt_expand_loc_dummy): Clear ignore_cur_loc field.
> (emit_note_insn_var_location): Adjust vt_expand_loc callers.
> (emit_notes_in_bb) <case MO_CALL>: Add NOTE_INSN_CALL_ARG_LOCATION
> note for all calls.
> (vt_add_function_parameter): Use cselib_lookup_from_insn.
> If dv is a VALUE, enter into hash table also ENTRY_VALUE for the
> argument. Don't call cselib_preserve_only_values and
> cselib_reset_table.
> (note_register_arguments): New function.
> (vt_initialize): Compute argument_reg_set. Call
> vt_add_function_parameters before processing basic blocks instead of
> afterwards. For calls call prepare_call_arguments before calling
> cselib_process_insn.
> * print-rtl.c (print_rtx): Handle NOTE_INSN_CALL_ARG_LOCATION.
> * Makefile.in (dwarf2out.o): Depend on $(CFGLAYOUT_H).
> (var-tracking.o): Depend on $(TM_P_H).
> * cfglayout.h (insn_scope): New prototype.
> * gengtype.c (adjust_field_rtx_def): Handle NOTE_INSN_CALL_ARG_LOCATION.
> * cfglayout.c (insn_scope): No longer static.
> * insn-notes.def (CALL_ARG_LOCATION): New.
> * calls.c (expand_call, emit_library_call_value_1): Put USEs for
> MEM arguments into CALL_INSN_FUNCTION_USAGE unconditionally.
> * integrate.c (set_block_origin_self, set_block_abstract_flags): Do
> nothing for DECL_EXTERNAL BLOCK_VARS.
> cp/
> * cp-objcp-common.c (cp_function_decl_explicit_p): Don't crash if
> DECL_LANG_SPECIFIC is NULL.
> include/
> * dwarf2.h (DW_TAG_GNU_call_site, DW_TAG_GNU_call_site_parameter,
> DW_AT_GNU_call_site_value, DW_AT_GNU_call_site_data_value,
> DW_AT_GNU_call_site_target, DW_AT_GNU_call_site_target_clobbered,
> DW_AT_GNU_tail_call, DW_AT_GNU_all_tail_call_sites,
> DW_AT_GNU_all_call_sites,, DW_AT_GNU_all_source_call_sites,
> DW_OP_GNU_entry_value): New.
>
> --- gcc/cp/cp-objcp-common.c.jj 2010-07-28 10:35:56.000000000 +0200
> +++ gcc/cp/cp-objcp-common.c 2010-08-13 12:44:17.000000000 +0200
> @@ -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));
> }
>
> --- gcc/Makefile.in.jj 2010-12-14 08:11:40.000000000 +0100
> +++ gcc/Makefile.in 2010-12-22 10:18:56.000000000 +0100
> @@ -2979,7 +2979,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)
> @@ -3208,7 +3208,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) $(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) \
> $(DIAGNOSTIC_CORE_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \
> --- gcc/print-rtl.c.jj 2010-08-13 10:18:21.000000000 +0200
> +++ gcc/print-rtl.c 2010-08-13 12:44:17.000000000 +0200
> @@ -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));
> --- gcc/rtl.def.jj 2010-08-13 10:18:21.000000000 +0200
> +++ gcc/rtl.def 2010-08-13 12:44:17.000000000 +0200
> @@ -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
> --- gcc/final.c.jj 2010-08-13 10:15:19.000000000 +0200
> +++ gcc/final.c 2010-08-13 12:44:17.000000000 +0200
> @@ -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)))
> --- gcc/var-tracking.c.jj 2010-12-22 09:54:58.000000000 +0100
> +++ gcc/var-tracking.c 2010-12-22 10:24:03.000000000 +0100
> @@ -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 hashval_t variable_htab_hash (const void *);
> static int variable_htab_eq (const void *, const void *);
> static void variable_htab_free (void *);
> @@ -659,11 +661,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;
>
> @@ -4958,6 +4964,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
> @@ -5307,10 +5316,22 @@ 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)
> + && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
> + {
> + gcc_checking_assert (type == MO_VAL_SET);
> + mo.u.loc = gen_rtx_SET (VOIDmode, loc, SET_SRC (expr));
> + }
> }
> else
> {
> - if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
> + if (GET_CODE (expr) == SET
> + && SET_DEST (expr) == loc
> + && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
> src = var_lowpart (mode2, SET_SRC (expr));
> loc = var_lowpart (mode2, loc);
>
> @@ -5368,7 +5389,9 @@ add_stores (rtx loc, const_rtx expr, voi
> }
> else
> {
> - if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
> + if (GET_CODE (expr) == SET
> + && SET_DEST (expr) == loc
> + && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
> src = var_lowpart (mode2, SET_SRC (expr));
> loc = var_lowpart (mode2, loc);
>
> @@ -5523,6 +5546,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
> @@ -5592,7 +5804,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);
> @@ -6908,6 +7121,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
> @@ -6921,6 +7138,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;
> @@ -6995,7 +7213,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)
> {
> @@ -7010,12 +7228,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)
> {
> @@ -7037,7 +7259,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)
> {
> @@ -7058,7 +7281,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;
>
> @@ -7068,6 +7291,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);
>
> @@ -7089,6 +7313,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;
> @@ -7159,7 +7384,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;
> @@ -7189,7 +7414,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;
> @@ -7643,6 +7868,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:
> @@ -8076,7 +8329,8 @@ vt_add_function_parameter (tree parm)
> if (offset)
> return;
>
> - 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. */
> @@ -8097,6 +8351,36 @@ vt_add_function_parameter (tree parm)
> 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))
> {
> @@ -8130,13 +8414,6 @@ vt_add_function_parameters (void)
> && DECL_NAMELESS (vexpr))
> vt_add_function_parameter (vexpr);
> }
> -
> - 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. */
> @@ -8164,6 +8441,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
> @@ -8266,6 +8560,8 @@ vt_initialize (void)
> valvar_pool = NULL;
> }
>
> + CLEAR_HARD_REG_SET (argument_reg_set);
> +
> if (!frame_pointer_needed)
> {
> rtx reg, elim;
> @@ -8312,9 +8608,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;
> @@ -8375,6 +8680,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))
> {
> @@ -8425,7 +8732,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;
> }
> --- gcc/calls.c.jj 2010-07-22 11:35:37.000000000 +0200
> +++ gcc/calls.c 2010-08-13 12:44:17.000000000 +0200
> @@ -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);
> }
> }
>
> --- gcc/cfglayout.h.jj 2010-03-31 13:11:56.000000000 +0200
> +++ gcc/cfglayout.h 2010-08-13 12:44:17.000000000 +0200
> @@ -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 *,
> --- gcc/insn-notes.def.jj 2010-03-31 13:11:55.000000000 +0200
> +++ gcc/insn-notes.def 2010-08-13 12:44:17.000000000 +0200
> @@ -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. */
> --- gcc/gengtype.c.jj 2010-08-11 21:08:06.000000000 +0200
> +++ gcc/gengtype.c 2010-08-13 12:44:17.000000000 +0200
> @@ -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;
>
> --- gcc/dwarf2out.c.jj 2010-12-22 09:54:58.000000000 +0100
> +++ gcc/dwarf2out.c 2010-12-22 10:17:25.000000000 +0100
> @@ -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;
> @@ -4794,6 +4795,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>";
> @@ -4900,6 +4903,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
> @@ -5015,6 +5020,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;
> }
> @@ -5053,6 +5064,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
> @@ -5282,6 +5295,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;
> @@ -5421,6 +5439,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;
>
> @@ -6039,10 +6058,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. */
> @@ -6821,6 +6863,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>";
> }
> @@ -7065,6 +7111,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";
> @@ -13878,6 +13940,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. */
> @@ -17748,8 +17830,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);
> }
> @@ -18778,6 +18863,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);
> @@ -18792,6 +18879,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. */
> @@ -18816,6 +18909,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 ();
> }
>
> @@ -18891,6 +18987,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). */
>
> @@ -19269,12 +19402,113 @@ 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);
>
> current_function_has_inlines = 0;
> decls_for_scope (outer_scope, subr_die, 0);
> +
> + 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);
> @@ -19663,6 +19897,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);
>
> @@ -19693,6 +19935,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);
> @@ -21304,7 +21553,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);
> }
>
> @@ -21656,16 +21909,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. */
> @@ -21677,12 +21949,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
> @@ -21695,7 +21975,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
> {
> @@ -21731,6 +22047,8 @@ dwarf2out_begin_function (tree fun)
> }
>
> 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
> @@ -22531,9 +22849,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))
> @@ -22625,6 +22950,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;
> --- gcc/cfglayout.c.jj 2010-06-07 11:25:05.000000000 +0200
> +++ gcc/cfglayout.c 2010-08-13 12:44:17.000000000 +0200
> @@ -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));
> --- gcc/integrate.c.jj 2010-12-02 13:15:24.000000000 +0100
> +++ gcc/integrate.c 2010-12-23 12:41:52.903882520 +0100
> @@ -112,7 +112,8 @@ set_block_origin_self (tree stmt)
> for (local_decl = BLOCK_VARS (stmt);
> local_decl != NULL_TREE;
> local_decl = DECL_CHAIN (local_decl))
> - set_decl_origin_self (local_decl); /* Potential recursion. */
> + if (! DECL_EXTERNAL (local_decl))
> + set_decl_origin_self (local_decl); /* Potential recursion. */
> }
>
> {
> @@ -173,7 +174,8 @@ set_block_abstract_flags (tree stmt, int
> for (local_decl = BLOCK_VARS (stmt);
> local_decl != NULL_TREE;
> local_decl = DECL_CHAIN (local_decl))
> - set_decl_abstract_flags (local_decl, setting);
> + if (! DECL_EXTERNAL (local_decl))
> + set_decl_abstract_flags (local_decl, setting);
>
> for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
> {
> --- include/dwarf2.h.jj 2010-08-13 10:18:27.000000000 +0200
> +++ include/dwarf2.h 2010-08-13 12:44:22.000000000 +0200
> @@ -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,
>
> Jakub
>
More information about the Gcc-patches
mailing list