diff mbox

Updated DW_OP_GNU_entry_value/DW_TAG_GNU_call_site patch

Message ID 20101223205351.GK16156@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Dec. 23, 2010, 8:53 p.m. UTC
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.

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.


	Jakub

Comments

Richard Biener Dec. 26, 2010, 10:08 p.m. UTC | #1
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
>
Jakub Jelinek Dec. 27, 2010, 12:52 p.m. UTC | #2
On Sun, Dec 26, 2010 at 11:08:02PM +0100, Richard Guenther wrote:
> 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?

Originally it was meant for 4.6, it was posted to gcc-patches already in mid
August, but I agree it is now too late for this for 4.6.  That said, I hope
it can be resolved for early stage 1.

	Jakub
diff mbox

Patch

--- 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,