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