summaryrefslogtreecommitdiff
path: root/gcc/dwarf2out.c
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2009-09-03 07:15:51 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2009-09-03 07:15:51 +0000
commit43ee3f43c8355e623faca36246804e55a784b985 (patch)
treebe310b3c549e4a26b6cc910f7f7dc8dcbd09a174 /gcc/dwarf2out.c
parentc5f9099f3c8c8e7e3a89952504f01eec289117bd (diff)
downloadgcc-43ee3f43c8355e623faca36246804e55a784b985.tar.gz
2009-09-03 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 151367 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@151369 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/dwarf2out.c')
-rw-r--r--gcc/dwarf2out.c1230
1 files changed, 1112 insertions, 118 deletions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index aad6ee7716a..fd386dd99d1 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -407,6 +407,10 @@ struct GTY(()) indirect_string_node {
static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
+/* True if the compilation unit has location entries that reference
+ debug strings. */
+static GTY(()) bool debug_str_hash_forced = false;
+
static GTY(()) int dw2_string_counter;
static GTY(()) unsigned long dwarf2out_cfi_label_num;
@@ -2992,6 +2996,23 @@ switch_to_eh_frame_section (bool back)
}
}
+/* Switch [BACK] to the eh or debug frame table section, depending on
+ FOR_EH. */
+
+static void
+switch_to_frame_table_section (int for_eh, bool back)
+{
+ if (for_eh)
+ switch_to_eh_frame_section (back);
+ else
+ {
+ if (!debug_frame_section)
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ switch_to_section (debug_frame_section);
+ }
+}
+
/* Output a Call Frame Information opcode and its operand(s). */
static void
@@ -3560,23 +3581,6 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
j += 2;
}
-
-/* Switch [BACK] to the eh or debug frame table section, depending on
- FOR_EH. */
-static void
-switch_to_frame_table_section (int for_eh, bool back)
-{
- if (for_eh)
- switch_to_eh_frame_section (back);
- else
- {
- if (!debug_frame_section)
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
- switch_to_section (debug_frame_section);
- }
-}
-
/* Output the call frame information used to record information
that relates to calculating the frame pointer, and records the
location of saved registers. */
@@ -4142,15 +4146,6 @@ enum dw_val_class
dw_val_class_file
};
-/* Describe a double word constant value. */
-/* ??? Every instance of long_long in the code really means CONST_DOUBLE. */
-
-typedef struct GTY(()) dw_long_long_struct {
- unsigned long hi;
- unsigned long low;
-}
-dw_long_long_const;
-
/* Describe a floating point constant value, or a vector constant value. */
typedef struct GTY(()) dw_vec_struct {
@@ -4173,7 +4168,7 @@ typedef struct GTY(()) dw_val_struct {
dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
HOST_WIDE_INT GTY ((default)) val_int;
unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
- dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
+ rtx GTY ((tag ("dw_val_class_long_long"))) val_long_long;
dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
struct dw_val_die_union
{
@@ -4528,6 +4523,10 @@ dwarf_stack_op_name (unsigned int op)
return "DW_OP_call4";
case DW_OP_call_ref:
return "DW_OP_call_ref";
+ case DW_OP_implicit_value:
+ return "DW_OP_implicit_value";
+ case DW_OP_stack_value:
+ return "DW_OP_stack_value";
case DW_OP_form_tls_address:
return "DW_OP_form_tls_address";
case DW_OP_call_frame_cfa:
@@ -4738,6 +4737,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
case DW_OP_call_ref:
size += DWARF2_ADDR_SIZE;
break;
+ case DW_OP_implicit_value:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+ + loc->dw_loc_oprnd1.v.val_unsigned;
+ break;
default:
break;
}
@@ -4773,6 +4776,10 @@ size_of_locs (dw_loc_descr_ref loc)
return size;
}
+#ifdef DWARF2_DEBUGGING_INFO
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+#endif
+
/* Output location description stack opcode's operands (if any). */
static void
@@ -4794,7 +4801,7 @@ output_loc_operands (dw_loc_descr_ref loc)
break;
case DW_OP_const8u:
case DW_OP_const8s:
- gcc_assert (HOST_BITS_PER_LONG >= 64);
+ gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
dw2_asm_output_data (8, val1->v.val_int, NULL);
break;
case DW_OP_skip:
@@ -4808,6 +4815,60 @@ output_loc_operands (dw_loc_descr_ref loc)
dw2_asm_output_data (2, offset, NULL);
}
break;
+ case DW_OP_implicit_value:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ switch (val2->val_class)
+ {
+ case dw_val_class_const:
+ dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
+ break;
+ case dw_val_class_vec:
+ {
+ unsigned int elt_size = val2->v.val_vec.elt_size;
+ unsigned int len = val2->v.val_vec.length;
+ unsigned int i;
+ unsigned char *p;
+
+ if (elt_size > sizeof (HOST_WIDE_INT))
+ {
+ elt_size /= 2;
+ len *= 2;
+ }
+ for (i = 0, p = val2->v.val_vec.array;
+ i < len;
+ i++, p += elt_size)
+ dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+ "fp or vector constant word %u", i);
+ }
+ break;
+ case dw_val_class_long_long:
+ {
+ unsigned HOST_WIDE_INT first, second;
+
+ if (WORDS_BIG_ENDIAN)
+ {
+ first = CONST_DOUBLE_HIGH (val2->v.val_long_long);
+ second = CONST_DOUBLE_LOW (val2->v.val_long_long);
+ }
+ else
+ {
+ first = CONST_DOUBLE_LOW (val2->v.val_long_long);
+ second = CONST_DOUBLE_HIGH (val2->v.val_long_long);
+ }
+ dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+ first, "long long constant");
+ dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
+ second, NULL);
+ }
+ break;
+ case dw_val_class_addr:
+ gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
#else
case DW_OP_const2u:
case DW_OP_const2s:
@@ -4817,6 +4878,7 @@ output_loc_operands (dw_loc_descr_ref loc)
case DW_OP_const8s:
case DW_OP_skip:
case DW_OP_bra:
+ case DW_OP_implicit_value:
/* We currently don't make any attempt to make sure these are
aligned properly like we do for the main unwind info, so
don't support emitting things larger than a byte if we're
@@ -4948,6 +5010,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
+ case DW_OP_implicit_value:
/* We cannot output addresses in .cfi_escape, only bytes. */
gcc_unreachable ();
@@ -4974,7 +5037,7 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
case DW_OP_const8u:
case DW_OP_const8s:
- gcc_assert (HOST_BITS_PER_LONG >= 64);
+ gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
fputc (',', asm_out_file);
dw2_asm_output_data_raw (8, val1->v.val_int);
break;
@@ -5551,6 +5614,14 @@ static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
The key is DECL_UID() ^ die_parent. */
static GTY ((param_is (struct die_struct))) htab_t common_block_die_table;
+typedef struct GTY(()) die_arg_entry_struct {
+ dw_die_ref die;
+ tree arg;
+} die_arg_entry;
+
+DEF_VEC_O(die_arg_entry);
+DEF_VEC_ALLOC_O(die_arg_entry,gc);
+
/* Node of the variable location list. */
struct GTY ((chain_next ("%h.next"))) var_loc_node {
rtx GTY (()) var_loc_note;
@@ -5685,6 +5756,8 @@ static GTY(()) int label_num;
/* Cached result of previous call to lookup_filename. */
static GTY(()) struct dwarf_file_data * file_table_last_lookup;
+static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table;
+
#ifdef DWARF2_DEBUGGING_INFO
/* Offset from the "steady-state frame pointer" to the frame base,
@@ -5709,8 +5782,7 @@ static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
static inline HOST_WIDE_INT AT_int (dw_attr_ref);
static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
-static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
- unsigned long);
+static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, rtx);
static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
unsigned int, unsigned char *);
static hashval_t debug_str_do_hash (const void *);
@@ -5826,6 +5898,7 @@ static dw_die_ref base_type_die (tree);
static int is_base_type (tree);
static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref);
static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
+static dw_die_ref generic_parameter_die (tree, tree, dw_die_ref, int);
static int type_is_enum (const_tree);
static unsigned int dbx_reg_number (const_rtx);
static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
@@ -5841,7 +5914,8 @@ static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
enum var_init_status);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
enum var_init_status);
-static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status);
+static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
+ enum var_init_status);
static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
static dw_loc_descr_ref loc_descriptor_from_tree (tree);
static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
@@ -5855,12 +5929,12 @@ static void add_AT_location_description (dw_die_ref, enum dwarf_attribute,
static void add_data_member_location_attribute (dw_die_ref, tree);
static void add_const_value_attribute (dw_die_ref, rtx);
static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
-static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
static void insert_float (const_rtx, unsigned char *);
static rtx rtl_for_decl_location (tree);
static void add_location_or_const_value_attribute (dw_die_ref, tree,
enum dwarf_attribute);
static void tree_add_const_value_attribute (dw_die_ref, tree);
+static void tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
static void add_name_attribute (dw_die_ref, const char *);
static void add_comp_dir_attribute (dw_die_ref);
static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
@@ -5924,6 +5998,8 @@ static dw_die_ref declare_in_namespace (tree, dw_die_ref);
static struct dwarf_file_data * lookup_filename (const char *);
static void retry_incomplete_types (void);
static void gen_type_die_for_member (tree, tree, dw_die_ref);
+static tree make_ith_pack_parameter_name (tree, int);
+static void gen_generic_params_dies (tree);
static void splice_child_die (dw_die_ref, dw_die_ref);
static int file_info_cmp (const void *, const void *);
static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
@@ -5941,6 +6017,8 @@ static void prune_unused_types_walk_attribs (dw_die_ref);
static void prune_unused_types_prune (dw_die_ref);
static void prune_unused_types (void);
static int maybe_emit_file (struct dwarf_file_data *fd);
+static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree);
+static void gen_remaining_tmpl_value_param_die_attribute (void);
/* Section names used to hold DWARF debugging information. */
#ifndef DEBUG_INFO_SECTION
@@ -6237,6 +6315,8 @@ dwarf_tag_name (unsigned int tag)
return "DW_TAG_GNU_BINCL";
case DW_TAG_GNU_EINCL:
return "DW_TAG_GNU_EINCL";
+ case DW_TAG_GNU_template_template_param:
+ return "DW_TAG_GNU_template_template_param";
default:
return "DW_TAG_<unknown>";
}
@@ -6438,6 +6518,8 @@ dwarf_attr_name (unsigned int attr)
return "DW_AT_body_end";
case DW_AT_GNU_vector:
return "DW_AT_GNU_vector";
+ case DW_AT_GNU_template_name:
+ return "DW_AT_GNU_template_name";
case DW_AT_VMS_rtnbeg_pd_address:
return "DW_AT_VMS_rtnbeg_pd_address";
@@ -6632,14 +6714,13 @@ AT_unsigned (dw_attr_ref a)
static inline void
add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
- long unsigned int val_hi, long unsigned int val_low)
+ rtx val_const_double)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_long_long;
- attr.dw_attr_val.v.val_long_long.hi = val_hi;
- attr.dw_attr_val.v.val_long_long.low = val_low;
+ attr.dw_attr_val.v.val_long_long = val_const_double;
add_dwarf_attr (die, &attr);
}
@@ -6674,6 +6755,8 @@ debug_str_eq (const void *x1, const void *x2)
(const char *)x2) == 0;
}
+/* Add STR to the indirect string hash table. */
+
static struct indirect_string_node *
find_AT_string (const char *str)
{
@@ -6716,6 +6799,37 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
add_dwarf_attr (die, &attr);
}
+/* Create a label for an indirect string node, ensuring it is going to
+ be output, unless its reference count goes down to zero. */
+
+static inline void
+gen_label_for_indirect_string (struct indirect_string_node *node)
+{
+ char label[32];
+
+ if (node->label)
+ return;
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
+ node->label = xstrdup (label);
+}
+
+/* Create a SYMBOL_REF rtx whose value is the initial address of a
+ debug string STR. */
+
+static inline rtx
+get_debug_string_label (const char *str)
+{
+ struct indirect_string_node *node = find_AT_string (str);
+
+ debug_str_hash_forced = true;
+
+ gen_label_for_indirect_string (node);
+
+ return gen_rtx_SYMBOL_REF (Pmode, node->label);
+}
+
static inline const char *
AT_string (dw_attr_ref a)
{
@@ -6731,7 +6845,6 @@ AT_string_form (dw_attr_ref a)
{
struct indirect_string_node *node;
unsigned int len;
- char label[32];
gcc_assert (a && AT_class (a) == dw_val_class_str);
@@ -6754,9 +6867,7 @@ AT_string_form (dw_attr_ref a)
&& (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
return node->form = DW_FORM_string;
- ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
- ++dw2_string_counter;
- node->label = xstrdup (label);
+ gen_label_for_indirect_string (node);
return node->form = DW_FORM_strp;
}
@@ -7469,9 +7580,10 @@ print_die (dw_die_ref die, FILE *outfile)
fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
break;
case dw_val_class_long_long:
- fprintf (outfile, "constant (%lu,%lu)",
- a->dw_attr_val.v.val_long_long.hi,
- a->dw_attr_val.v.val_long_long.low);
+ fprintf (outfile, "constant (" HOST_WIDE_INT_PRINT_UNSIGNED
+ "," HOST_WIDE_INT_PRINT_UNSIGNED ")",
+ CONST_DOUBLE_HIGH (a->dw_attr_val.v.val_long_long),
+ CONST_DOUBLE_LOW (a->dw_attr_val.v.val_long_long));
break;
case dw_val_class_vec:
fprintf (outfile, "floating-point or vector constant");
@@ -7628,7 +7740,8 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
CHECKSUM (at->dw_attr_val.v.val_unsigned);
break;
case dw_val_class_long_long:
- CHECKSUM (at->dw_attr_val.v.val_long_long);
+ CHECKSUM (CONST_DOUBLE_HIGH (at->dw_attr_val.v.val_long_long));
+ CHECKSUM (CONST_DOUBLE_LOW (at->dw_attr_val.v.val_long_long));
break;
case dw_val_class_vec:
CHECKSUM (at->dw_attr_val.v.val_vec);
@@ -7728,8 +7841,10 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
case dw_val_class_unsigned_const:
return v1->v.val_unsigned == v2->v.val_unsigned;
case dw_val_class_long_long:
- return v1->v.val_long_long.hi == v2->v.val_long_long.hi
- && v1->v.val_long_long.low == v2->v.val_long_long.low;
+ return CONST_DOUBLE_HIGH (v1->v.val_long_long)
+ == CONST_DOUBLE_HIGH (v2->v.val_long_long)
+ && CONST_DOUBLE_LOW (v1->v.val_long_long)
+ == CONST_DOUBLE_LOW (v2->v.val_long_long);
case dw_val_class_vec:
if (v1->v.val_vec.length != v2->v.val_vec.length
|| v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
@@ -8338,7 +8453,7 @@ size_of_die (dw_die_ref die)
size += constant_size (AT_unsigned (a));
break;
case dw_val_class_long_long:
- size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
+ size += 1 + 2*HOST_BITS_PER_WIDE_INT/HOST_BITS_PER_CHAR; /* block */
break;
case dw_val_class_vec:
size += constant_size (a->dw_attr_val.v.val_vec.length
@@ -8820,23 +8935,24 @@ output_die (dw_die_ref die)
unsigned HOST_WIDE_INT first, second;
dw2_asm_output_data (1,
- 2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ 2 * HOST_BITS_PER_WIDE_INT
+ / HOST_BITS_PER_CHAR,
"%s", name);
if (WORDS_BIG_ENDIAN)
{
- first = a->dw_attr_val.v.val_long_long.hi;
- second = a->dw_attr_val.v.val_long_long.low;
+ first = CONST_DOUBLE_HIGH (a->dw_attr_val.v.val_long_long);
+ second = CONST_DOUBLE_LOW (a->dw_attr_val.v.val_long_long);
}
else
{
- first = a->dw_attr_val.v.val_long_long.low;
- second = a->dw_attr_val.v.val_long_long.hi;
+ first = CONST_DOUBLE_LOW (a->dw_attr_val.v.val_long_long);
+ second = CONST_DOUBLE_HIGH (a->dw_attr_val.v.val_long_long);
}
- dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
first, "long long constant");
- dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
second, NULL);
}
break;
@@ -10353,6 +10469,189 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
return mod_type_die;
}
+/* Generate a new name for the parameter pack name NAME (an
+ IDENTIFIER_NODE) that incorporates its */
+
+static tree
+make_ith_pack_parameter_name (tree name, int i)
+{
+ /* Munge the name to include the parameter index. */
+#define NUMBUF_LEN 128
+ char numbuf[NUMBUF_LEN];
+ char* newname;
+ int newname_len;
+
+ snprintf (numbuf, NUMBUF_LEN, "%i", i);
+ newname_len = IDENTIFIER_LENGTH (name)
+ + strlen (numbuf) + 2;
+ newname = (char*) alloca (newname_len);
+ snprintf (newname, newname_len,
+ "%s#%i", IDENTIFIER_POINTER (name), i);
+ return get_identifier (newname);
+}
+
+/* Generate DIEs for the generic parameters of T.
+ T must be either a generic type or a generic function.
+ See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more. */
+
+static void
+gen_generic_params_dies (tree t)
+{
+ tree parms, args;
+ int parms_num, i;
+ dw_die_ref die = NULL;
+
+ if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t)))
+ return;
+
+ if (TYPE_P (t))
+ die = lookup_type_die (t);
+ else if (DECL_P (t))
+ die = lookup_decl_die (t);
+
+ gcc_assert (die);
+
+ parms = lang_hooks.get_innermost_generic_parms (t);
+ if (!parms)
+ /* T has no generic parameter. It means T is neither a generic type
+ or function. End of story. */
+ return;
+
+ parms_num = TREE_VEC_LENGTH (parms);
+ args = lang_hooks.get_innermost_generic_args (t);
+ for (i = 0; i < parms_num; i++)
+ {
+ tree parm, arg;
+
+ parm = TREE_VEC_ELT (parms, i);
+ arg = TREE_VEC_ELT (args, i);
+ if (parm && TREE_VALUE (parm) && arg)
+ {
+ tree pack_elems =
+ lang_hooks.types.get_argument_pack_elems (arg);
+ if (pack_elems)
+ {
+ /* So ARG is an argument pack and the elements of that pack
+ are stored in PACK_ELEMS. */
+ int i, len;
+
+ len = TREE_VEC_LENGTH (pack_elems);
+ for (i = 0; i < len; i++)
+ generic_parameter_die (TREE_VALUE (parm),
+ TREE_VEC_ELT (pack_elems, i),
+ die, i);
+ }
+ else /* Arg is not an argument pack. */
+ generic_parameter_die (TREE_VALUE (parm),
+ arg, die,
+ -1/* Not a param pack. */);
+ }
+ }
+}
+
+/* Create and return a DIE for PARM which should be
+ the representation of a generic type parameter.
+ For instance, in the C++ front end, PARM would be a template parameter.
+ ARG is the argument to PARM.
+ PARENT_DIE is the parent DIE which the new created DIE should be added to,
+ as a child node.
+ PACK_ELEM_INDEX is >= 0 if PARM is a generic parameter pack, and if ARG
+ is one of the unpacked elements of the parameter PACK. In that case,
+ PACK_ELEM_INDEX is the index of ARG in the parameter pack. */
+
+static dw_die_ref
+generic_parameter_die (tree parm, tree arg, dw_die_ref parent_die,
+ int pack_elem_index)
+{
+ dw_die_ref tmpl_die = NULL;
+ const char *name = NULL;
+
+ if (!parm || !DECL_NAME (parm) || !arg)
+ return NULL;
+
+ /* We support non-type generic parameters and arguments,
+ type generic parameters and arguments, as well as
+ generic generic parameters (a.k.a. template template parameters in C++)
+ and arguments. */
+ if (TREE_CODE (parm) == PARM_DECL)
+ /* PARM is a nontype generic parameter */
+ tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm);
+ else if (TREE_CODE (parm) == TYPE_DECL)
+ /* PARM is a type generic parameter. */
+ tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm);
+ else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+ /* PARM is a generic generic parameter.
+ Its DIE is a GNU extension. It shall have a
+ DW_AT_name attribute to represent the name of the template template
+ parameter, and a DW_AT_GNU_template_name attribute to represent the
+ name of the template template argument. */
+ tmpl_die = new_die (DW_TAG_GNU_template_template_param,
+ parent_die, parm);
+ else
+ gcc_unreachable ();
+
+ if (tmpl_die)
+ {
+ tree tmpl_type;
+
+ if (pack_elem_index >= 0)
+ {
+ /* PARM is an element of a parameter pack.
+ Generate a name for it. */
+ tree identifier = make_ith_pack_parameter_name (DECL_NAME (parm),
+ pack_elem_index);
+ if (identifier)
+ name = IDENTIFIER_POINTER (identifier);
+ }
+ else
+ name = IDENTIFIER_POINTER (DECL_NAME (parm));
+
+ gcc_assert (name);
+ add_AT_string (tmpl_die, DW_AT_name, name);
+
+ if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm))
+ {
+ /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter
+ TMPL_DIE should have a child DW_AT_type attribute that is set
+ to the type of the argument to PARM, which is ARG.
+ If PARM is a type generic parameter, TMPL_DIE should have a
+ child DW_AT_type that is set to ARG. */
+ tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg);
+ add_type_attribute (tmpl_die, tmpl_type, 0,
+ TREE_THIS_VOLATILE (tmpl_type),
+ parent_die);
+ }
+ else
+ {
+ /* So TMPL_DIE is a DIE representing a
+ a generic generic template parameter, a.k.a template template
+ parameter in C++ and arg is a template. */
+
+ /* The DW_AT_GNU_template_name attribute of the DIE must be set
+ to the name of the argument. */
+ name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1);
+ add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
+ }
+
+ if (TREE_CODE (parm) == PARM_DECL)
+ /* So PARM is a non-type generic parameter.
+ DWARF3 5.6.8 says we must set a DW_AT_const_value child
+ attribute of TMPL_DIE which value represents the value
+ of ARG.
+ We must be careful here:
+ The value of ARG might reference some function decls.
+ We might currently be emitting debug info for a generic
+ type and types are emitted before function decls, we don't
+ know if the function decls referenced by ARG will actually be
+ emitted after cgraph computations.
+ So must defer the generation of the DW_AT_const_value to
+ after cgraph is ready. */
+ append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg);
+ }
+
+ return tmpl_die;
+}
+
/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
an enumerated type. */
@@ -10719,6 +11018,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
{
dw_loc_descr_ref mem_loc_result = NULL;
enum dwarf_location_atom op;
+ dw_loc_descr_ref op0, op1;
/* Note that for a dynamically sized array, the location we will generate a
description of here will be the lowest numbered location which is
@@ -10744,6 +11044,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
rtl = XEXP (rtl, 0);
+ if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+ break;
/* ... fall through ... */
@@ -10775,6 +11077,29 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
}
break;
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == 0)
+ break;
+ else
+ {
+ int shift = DWARF2_ADDR_SIZE
+ - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+ shift *= BITS_PER_UNIT;
+ if (GET_CODE (rtl) == SIGN_EXTEND)
+ op = DW_OP_shra;
+ else
+ op = DW_OP_shr;
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+ add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ }
+ break;
+
case MEM:
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
VAR_INIT_STATUS_INITIALIZED);
@@ -10819,6 +11144,27 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
return 0;
}
+ if (GET_CODE (rtl) == SYMBOL_REF
+ && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+ {
+ dw_loc_descr_ref temp;
+
+ /* If this is not defined, we have no way to emit the data. */
+ if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
+ break;
+
+ temp = new_loc_descr (DW_OP_addr, 0, 0);
+ temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ temp->dw_loc_oprnd1.v.val_addr = rtl;
+ temp->dtprel = true;
+
+ mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+ add_loc_descr (&mem_loc_result, temp);
+
+ break;
+ }
+
+ symref:
mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
@@ -10873,10 +11219,22 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
/* If a pseudo-reg is optimized away, it is possible for it to
be replaced with a MEM containing a multiply or shift. */
+ case MINUS:
+ op = DW_OP_minus;
+ goto do_binop;
+
case MULT:
op = DW_OP_mul;
goto do_binop;
+ case DIV:
+ op = DW_OP_div;
+ goto do_binop;
+
+ case MOD:
+ op = DW_OP_mod;
+ goto do_binop;
+
case ASHIFT:
op = DW_OP_shl;
goto do_binop;
@@ -10889,21 +11247,54 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
op = DW_OP_shr;
goto do_binop;
+ case AND:
+ op = DW_OP_and;
+ goto do_binop;
+
+ case IOR:
+ op = DW_OP_or;
+ goto do_binop;
+
+ case XOR:
+ op = DW_OP_xor;
+ goto do_binop;
+
do_binop:
- {
- dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
- VAR_INIT_STATUS_INITIALIZED);
- dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
- VAR_INIT_STATUS_INITIALIZED);
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+ VAR_INIT_STATUS_INITIALIZED);
- if (op0 == 0 || op1 == 0)
- break;
+ if (op0 == 0 || op1 == 0)
+ break;
+
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, op1);
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ break;
+
+ case NOT:
+ op = DW_OP_not;
+ goto do_unop;
+
+ case ABS:
+ op = DW_OP_abs;
+ goto do_unop;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, op1);
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ case NEG:
+ op = DW_OP_neg;
+ goto do_unop;
+
+ do_unop:
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+
+ if (op0 == 0)
break;
- }
+
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ break;
case CONST_INT:
mem_loc_result = int_loc_descriptor (INTVAL (rtl));
@@ -10914,14 +11305,287 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
VAR_INIT_STATUS_INITIALIZED);
break;
+ case EQ:
+ op = DW_OP_eq;
+ goto do_scompare;
+
+ case GE:
+ op = DW_OP_ge;
+ goto do_scompare;
+
+ case GT:
+ op = DW_OP_gt;
+ goto do_scompare;
+
+ case LE:
+ op = DW_OP_le;
+ goto do_scompare;
+
+ case LT:
+ op = DW_OP_lt;
+ goto do_scompare;
+
+ case NE:
+ op = DW_OP_ne;
+ goto do_scompare;
+
+ do_scompare:
+ if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+ || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+ || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+ break;
+
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+
+ if (op0 == 0 || op1 == 0)
+ break;
+
+ if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+ {
+ int shift = DWARF2_ADDR_SIZE
+ - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+ shift *= BITS_PER_UNIT;
+ add_loc_descr (&op0, int_loc_descriptor (shift));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+ if (CONST_INT_P (XEXP (rtl, 1)))
+ op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
+ else
+ {
+ add_loc_descr (&op1, int_loc_descriptor (shift));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+ }
+ }
+
+ do_compare:
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, op1);
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ if (STORE_FLAG_VALUE != 1)
+ {
+ add_loc_descr (&mem_loc_result,
+ int_loc_descriptor (STORE_FLAG_VALUE));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+ }
+ break;
+
+ case GEU:
+ op = DW_OP_ge;
+ goto do_ucompare;
+
+ case GTU:
+ op = DW_OP_gt;
+ goto do_ucompare;
+
+ case LEU:
+ op = DW_OP_le;
+ goto do_ucompare;
+
+ case LTU:
+ op = DW_OP_lt;
+ goto do_ucompare;
+
+ do_ucompare:
+ if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+ || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+ || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+ break;
+
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+
+ if (op0 == 0 || op1 == 0)
+ break;
+
+ if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+ {
+ HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+ add_loc_descr (&op0, int_loc_descriptor (mask));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+ if (CONST_INT_P (XEXP (rtl, 1)))
+ op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
+ else
+ {
+ add_loc_descr (&op1, int_loc_descriptor (mask));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+ }
+ }
+ else
+ {
+ HOST_WIDE_INT bias = 1;
+ bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+ if (CONST_INT_P (XEXP (rtl, 1)))
+ op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
+ + INTVAL (XEXP (rtl, 1)));
+ else
+ add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+ }
+ goto do_compare;
+
+ case SMIN:
+ case SMAX:
+ case UMIN:
+ case UMAX:
+ if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) != MODE_INT
+ || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) > DWARF2_ADDR_SIZE
+ || GET_MODE (XEXP (rtl, 0)) != GET_MODE (XEXP (rtl, 1)))
+ break;
+
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+
+ if (op0 == 0 || op1 == 0)
+ break;
+
+ add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
+ if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
+ {
+ if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+ {
+ HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE (XEXP (rtl, 0)));
+ add_loc_descr (&op0, int_loc_descriptor (mask));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+ add_loc_descr (&op1, int_loc_descriptor (mask));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
+ }
+ else
+ {
+ HOST_WIDE_INT bias = 1;
+ bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
+ }
+ }
+ else if (GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) < DWARF2_ADDR_SIZE)
+ {
+ int shift = DWARF2_ADDR_SIZE
+ - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
+ shift *= BITS_PER_UNIT;
+ add_loc_descr (&op0, int_loc_descriptor (shift));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+ add_loc_descr (&op1, int_loc_descriptor (shift));
+ add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
+ }
+
+ if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
+ op = DW_OP_lt;
+ else
+ op = DW_OP_gt;
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, op1);
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ {
+ dw_loc_descr_ref bra_node, drop_node;
+
+ bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+ add_loc_descr (&mem_loc_result, bra_node);
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
+ drop_node = new_loc_descr (DW_OP_drop, 0, 0);
+ add_loc_descr (&mem_loc_result, drop_node);
+ bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
+ }
+ break;
+
+ case ZERO_EXTRACT:
+ case SIGN_EXTRACT:
+ if (CONST_INT_P (XEXP (rtl, 1))
+ && CONST_INT_P (XEXP (rtl, 2))
+ && ((unsigned) INTVAL (XEXP (rtl, 1))
+ + (unsigned) INTVAL (XEXP (rtl, 2))
+ <= GET_MODE_BITSIZE (GET_MODE (rtl)))
+ && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+ && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
+ {
+ int shift, size;
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == 0)
+ break;
+ if (GET_CODE (rtl) == SIGN_EXTRACT)
+ op = DW_OP_shra;
+ else
+ op = DW_OP_shr;
+ mem_loc_result = op0;
+ size = INTVAL (XEXP (rtl, 1));
+ shift = INTVAL (XEXP (rtl, 2));
+ if (BITS_BIG_ENDIAN)
+ shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+ - shift - size;
+ add_loc_descr (&mem_loc_result,
+ int_loc_descriptor (DWARF2_ADDR_SIZE - shift - size));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
+ add_loc_descr (&mem_loc_result,
+ int_loc_descriptor (DWARF2_ADDR_SIZE - size));
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ }
+ break;
+
+ case COMPARE:
+ case IF_THEN_ELSE:
+ case ROTATE:
+ case ROTATERT:
+ case TRUNCATE:
+ /* In theory, we could implement the above. */
+ /* DWARF cannot represent the unsigned compare operations
+ natively. */
+ case SS_MULT:
+ case US_MULT:
+ case SS_DIV:
+ case US_DIV:
+ case UDIV:
+ case UMOD:
+ case UNORDERED:
+ case ORDERED:
+ case UNEQ:
+ case UNGE:
+ case UNLE:
+ case UNLT:
+ case LTGT:
+ case FLOAT_EXTEND:
+ case FLOAT_TRUNCATE:
+ case FLOAT:
+ case UNSIGNED_FLOAT:
+ case FIX:
+ case UNSIGNED_FIX:
+ case FRACT_CONVERT:
+ case UNSIGNED_FRACT_CONVERT:
+ case SAT_FRACT:
+ case UNSIGNED_SAT_FRACT:
+ case SQRT:
+ case BSWAP:
+ case FFS:
+ case CLZ:
+ case CTZ:
+ case POPCOUNT:
+ case PARITY:
+ case ASM_OPERANDS:
case UNSPEC:
/* If delegitimize_address couldn't do anything with the UNSPEC, we
can't express it in the debug info. This can happen e.g. with some
TLS UNSPECs. */
break;
+ case CONST_STRING:
+ rtl = get_debug_string_label (XSTR (rtl, 0));
+ goto symref;
+
default:
+#ifdef ENABLE_CHECKING
+ print_rtl (stderr, rtl);
gcc_unreachable ();
+#else
+ break;
+#endif
}
if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
@@ -10937,8 +11601,10 @@ static dw_loc_descr_ref
concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
{
dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
- dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref x0_ref
+ = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref x1_ref
+ = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
if (x0_ref == 0 || x1_ref == 0)
return 0;
@@ -10970,7 +11636,7 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
dw_loc_descr_ref ref;
rtx x = XVECEXP (concatn, 0, i);
- ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
+ ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
if (ref == NULL)
return NULL;
@@ -10990,16 +11656,23 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
memory location we provide a Dwarf postfix expression describing how to
generate the (dynamic) address of the object onto the address stack.
+ MODE is mode of the decl if this loc_descriptor is going to be used in
+ .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+ allowed, VOIDmode otherwise.
+
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+loc_descriptor (rtx rtl, enum machine_mode mode,
+ enum var_init_status initialized)
{
dw_loc_descr_ref loc_result = NULL;
switch (GET_CODE (rtl))
{
case SUBREG:
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
/* The case of a subreg may arise when we have a local (register)
variable or a formal (register) parameter which doesn't quite fill
up an entire register. For now, just assume that it is
@@ -11033,7 +11706,8 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
/* Single part. */
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
- loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
+ initialized);
break;
}
@@ -11049,7 +11723,7 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
/* Create the first one, so we have something to add to. */
loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- initialized);
+ VOIDmode, initialized);
if (loc_result == NULL)
return NULL;
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
@@ -11059,7 +11733,7 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
dw_loc_descr_ref temp;
temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
- initialized);
+ VOIDmode, initialized);
if (temp == NULL)
return NULL;
add_loc_descr (&loc_result, temp);
@@ -11069,8 +11743,206 @@ loc_descriptor (rtx rtl, enum var_init_status initialized)
}
break;
+ case CONST_INT:
+ if (mode != VOIDmode && mode != BLKmode && dwarf_version >= 4)
+ {
+ HOST_WIDE_INT i = INTVAL (rtl);
+ int litsize;
+ if (i >= 0)
+ {
+ if (i <= 31)
+ litsize = 1;
+ else if (i <= 0xff)
+ litsize = 2;
+ else if (i <= 0xffff)
+ litsize = 3;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i <= 0xffffffff)
+ litsize = 5;
+ else
+ litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+ }
+ else
+ {
+ if (i >= -0x80)
+ litsize = 2;
+ else if (i >= -0x8000)
+ litsize = 3;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i >= -0x80000000)
+ litsize = 5;
+ else
+ litsize = 1 + size_of_sleb128 (i);
+ }
+ /* Determine if DW_OP_stack_value or DW_OP_implicit_value
+ is more compact. For DW_OP_stack_value we need:
+ litsize + 1 (DW_OP_stack_value) + 1 (DW_OP_bit_size)
+ + 1 (mode size)
+ and for DW_OP_implicit_value:
+ 1 (DW_OP_implicit_value) + 1 (length) + mode_size. */
+ if (DWARF2_ADDR_SIZE >= GET_MODE_SIZE (mode)
+ && litsize + 1 + 1 + 1 < 1 + 1 + GET_MODE_SIZE (mode))
+ {
+ loc_result = int_loc_descriptor (i);
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+ return loc_result;
+ }
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ GET_MODE_SIZE (mode), 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+ loc_result->dw_loc_oprnd2.v.val_int = i;
+ }
+ break;
+
+ case CONST_DOUBLE:
+ if (mode != VOIDmode && dwarf_version >= 4)
+ {
+ /* Note that a CONST_DOUBLE rtx could represent either an integer
+ or a floating-point constant. A CONST_DOUBLE is used whenever
+ the constant requires more than one word in order to be
+ adequately represented. We output CONST_DOUBLEs as blocks. */
+ if (GET_MODE (rtl) != VOIDmode)
+ mode = GET_MODE (rtl);
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ GET_MODE_SIZE (mode), 0);
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ unsigned int length = GET_MODE_SIZE (mode);
+ unsigned char *array = GGC_NEWVEC (unsigned char, length);
+
+ insert_float (rtl, array);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+ loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+ loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+ loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+ }
+ else
+ {
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_long_long;
+ loc_result->dw_loc_oprnd2.v.val_long_long = rtl;
+ }
+ }
+ break;
+
+ case CONST_VECTOR:
+ if (mode != VOIDmode && dwarf_version >= 4)
+ {
+ unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
+ unsigned int length = CONST_VECTOR_NUNITS (rtl);
+ unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
+ unsigned int i;
+ unsigned char *p;
+
+ mode = GET_MODE (rtl);
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_VECTOR_INT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ HOST_WIDE_INT lo, hi;
+
+ switch (GET_CODE (elt))
+ {
+ case CONST_INT:
+ lo = INTVAL (elt);
+ hi = -(lo < 0);
+ break;
+
+ case CONST_DOUBLE:
+ lo = CONST_DOUBLE_LOW (elt);
+ hi = CONST_DOUBLE_HIGH (elt);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (elt_size <= sizeof (HOST_WIDE_INT))
+ insert_int (lo, elt_size, p);
+ else
+ {
+ unsigned char *p0 = p;
+ unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+ gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+ if (WORDS_BIG_ENDIAN)
+ {
+ p0 = p1;
+ p1 = p;
+ }
+ insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+ insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+ }
+ }
+ break;
+
+ case MODE_VECTOR_FLOAT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ insert_float (elt, p);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ length * elt_size, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+ loc_result->dw_loc_oprnd2.v.val_vec.length = length;
+ loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
+ loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+ }
+ break;
+
+ case CONST:
+ if (mode == VOIDmode
+ || GET_CODE (XEXP (rtl, 0)) == CONST_INT
+ || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+ || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
+ {
+ loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+ break;
+ }
+ /* FALLTHROUGH */
+ case SYMBOL_REF:
+ if (GET_CODE (rtl) == SYMBOL_REF
+ && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+ break;
+ case LABEL_REF:
+ if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
+ && dwarf_version >= 4)
+ {
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ DWARF2_ADDR_SIZE, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr;
+ loc_result->dw_loc_oprnd2.v.val_addr = rtl;
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+ }
+ break;
+
default:
- gcc_unreachable ();
+ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode
+ && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
+ && dwarf_version >= 4)
+ {
+ /* Value expression. */
+ loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+ if (loc_result)
+ {
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+ }
+ }
+ break;
}
return loc_result;
@@ -11213,7 +12085,8 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
+ return loc_descriptor (rtl, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
@@ -11928,13 +12801,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
}
else
- {
- /* ??? We really should be using HOST_WIDE_INT throughout. */
- gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
-
- add_AT_long_long (die, DW_AT_const_value,
- CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
- }
+ add_AT_long_long (die, DW_AT_const_value, rtl);
}
break;
@@ -12010,9 +12877,18 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
break;
+ case CONST:
+ if (CONSTANT_P (XEXP (rtl, 0)))
+ {
+ add_const_value_attribute (die, XEXP (rtl, 0));
+ return;
+ }
+ /* FALLTHROUGH */
case SYMBOL_REF:
+ if (GET_CODE (rtl) == SYMBOL_REF
+ && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+ break;
case LABEL_REF:
- case CONST:
add_AT_addr (die, DW_AT_const_value, rtl);
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
@@ -12057,17 +12933,20 @@ reference_to_unused (tree * tp, int * walk_subtrees,
else if (!cgraph_global_info_ready
&& (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
return *tp;
- else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
+ else if (TREE_CODE (*tp) == VAR_DECL)
{
struct varpool_node *node = varpool_node (*tp);
if (!node->needed)
return *tp;
}
- else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
+ else if (TREE_CODE (*tp) == FUNCTION_DECL
&& (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
{
- struct cgraph_node *node = cgraph_node (*tp);
- if (node->process || TREE_ASM_WRITTEN (*tp))
+ /* The call graph machinery must have finished analyzing,
+ optimizing and gimplifying the CU by now.
+ So if *TP has no call graph node associated
+ to it, it means *TP will not be emitted. */
+ if (!cgraph_get_node (*tp))
return *tp;
}
else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp))
@@ -12555,7 +13434,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
else
initialized = VAR_INIT_STATUS_INITIALIZED;
- descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
+ descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+ initialized), decl);
list = new_loc_list (descr, node->label, node->next->label, secname, 1);
node = node->next;
@@ -12567,8 +13447,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
enum var_init_status initialized =
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
- decl);
+ descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+ initialized), decl);
add_loc_descr_to_loc_list (&list, descr,
node->label, node->next->label, secname);
}
@@ -12590,7 +13470,9 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
+ descr = loc_by_reference (loc_descriptor (varloc,
+ DECL_MODE (decl),
+ initialized),
decl);
add_loc_descr_to_loc_list (&list, descr,
node->label, endname, secname);
@@ -12619,7 +13501,17 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
enum var_init_status status;
node = loc_list->first;
status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
- descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
+ rtl = NOTE_VAR_LOCATION (node->var_loc_note);
+ if (GET_CODE (rtl) == VAR_LOCATION
+ && GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+ rtl = XEXP (XEXP (rtl, 1), 0);
+ if (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+ {
+ add_const_value_attribute (die, rtl);
+ return;
+ }
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
+ DECL_MODE (decl), status);
if (descr)
{
descr = loc_by_reference (descr, decl);
@@ -12639,7 +13531,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
}
/* None of that worked, so it must not really have a location;
try adding a constant value attribute from the DECL_INITIAL. */
- tree_add_const_value_attribute (die, decl);
+ tree_add_const_value_attribute_for_decl (die, decl);
}
/* Add VARIABLE and DIE into deferred locations list. */
@@ -12800,29 +13692,25 @@ native_encode_initializer (tree init, unsigned char *array, int size)
}
}
-/* If we don't have a copy of this variable in memory for some reason (such
- as a C++ member constant that doesn't have an out-of-line definition),
- we should tell the debugger about the constant value. */
+/* Attach a DW_AT_const_value attribute to DIE. The value of the
+ attribute is the const value T. */
static void
-tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
+tree_add_const_value_attribute (dw_die_ref die, tree t)
{
tree init;
- tree type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (t);
rtx rtl;
- if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
+ if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
return;
- init = DECL_INITIAL (decl);
- if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
- /* OK */;
- else
- return;
+ init = t;
+ gcc_assert (!DECL_P (init));
rtl = rtl_for_decl_init (init, type);
if (rtl)
- add_const_value_attribute (var_die, rtl);
+ add_const_value_attribute (die, rtl);
/* If the host and target are sane, try harder. */
else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
&& initializer_constant_valid_p (init, type))
@@ -12833,11 +13721,35 @@ tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
unsigned char *array = GGC_CNEWVEC (unsigned char, size);
if (native_encode_initializer (init, array, size))
- add_AT_vec (var_die, DW_AT_const_value, size, 1, array);
+ add_AT_vec (die, DW_AT_const_value, size, 1, array);
}
}
}
+/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the
+ attribute is the const value of T, where T is an integral constant
+ variable with static storage duration
+ (so it can't be a PARM_DECL or a RESULT_DECL). */
+
+static void
+tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
+{
+
+ if (!decl
+ || (TREE_CODE (decl) != VAR_DECL
+ && TREE_CODE (decl) != CONST_DECL))
+ return;
+
+ if (TREE_READONLY (decl)
+ && ! TREE_THIS_VOLATILE (decl)
+ && DECL_INITIAL (decl))
+ /* OK */;
+ else
+ return;
+
+ tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
+}
+
/* Convert the CFI instructions for the current function into a
location list. This is used for DW_AT_frame_base when we targeting
a dwarf2 consumer that does not support the dwarf3
@@ -14534,6 +15446,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
loc_descriptor_from_tree (cfun->static_chain_decl));
}
+ /* Generate child dies for template paramaters. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ gen_generic_params_dies (decl);
+
/* Now output descriptions of the arguments for this function. This gets
(unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
for a FUNCTION_DECL doesn't indicate cases where there was a trailing
@@ -14895,7 +15811,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
add_pubname (decl_or_origin, var_die);
}
else
- tree_add_const_value_attribute (var_die, decl_or_origin);
+ tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
}
/* Generate a DIE to represent a named constant. */
@@ -14913,7 +15829,7 @@ gen_const_die (tree decl, dw_die_ref context_die)
add_AT_flag (const_die, DW_AT_external, 1);
if (DECL_ARTIFICIAL (decl))
add_AT_flag (const_die, DW_AT_artificial, 1);
- tree_add_const_value_attribute (const_die, decl);
+ tree_add_const_value_attribute_for_decl (const_die, decl);
}
/* Generate a DIE to represent a label identifier. */
@@ -15332,6 +16248,11 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
else
remove_AT (type_die, DW_AT_declaration);
+ /* Generate child dies for template paramaters. */
+ if (debug_info_level > DINFO_LEVEL_TERSE
+ && COMPLETE_TYPE_P (type))
+ gen_generic_params_dies (type);
+
/* If this type has been completed, then give it a byte_size attribute and
then give a list of members. */
if (complete && !ns_decl)
@@ -16587,6 +17508,49 @@ maybe_emit_file (struct dwarf_file_data * fd)
return fd->emitted_number;
}
+/* Schedule generation of a DW_AT_const_value attribute to DIE.
+ That generation should happen after function debug info has been
+ generated. The value of the attribute is the constant value of ARG. */
+
+static void
+append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
+{
+ die_arg_entry entry;
+
+ if (!die || !arg)
+ return;
+
+ if (!tmpl_value_parm_die_table)
+ tmpl_value_parm_die_table
+ = VEC_alloc (die_arg_entry, gc, 32);
+
+ entry.die = die;
+ entry.arg = arg;
+ VEC_safe_push (die_arg_entry, gc,
+ tmpl_value_parm_die_table,
+ &entry);
+}
+
+/* Add a DW_AT_const_value attribute to DIEs that were scheduled
+ by append_entry_to_tmpl_value_parm_die_table. This function must
+ be called after function DIEs have been generated. */
+
+static void
+gen_remaining_tmpl_value_param_die_attribute (void)
+{
+ if (tmpl_value_parm_die_table)
+ {
+ unsigned i;
+ die_arg_entry *e;
+
+ for (i = 0;
+ VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e);
+ i++)
+ tree_add_const_value_attribute (e->die, e->arg);
+ }
+}
+
+
/* Replace DW_AT_name for the decl with name. */
static void
@@ -16620,10 +17584,11 @@ dwarf2out_set_name (tree decl, tree name)
static void
dwarf2out_var_location (rtx loc_note)
{
- char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
+ char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
struct var_loc_node *newloc;
rtx next_real;
static const char *last_label;
+ static const char *last_postcall_label;
static bool last_in_cold_section_p;
tree decl;
@@ -16639,27 +17604,38 @@ dwarf2out_var_location (rtx loc_note)
newloc = GGC_CNEW (struct var_loc_node);
/* If there were no real insns between note we processed last time
and this note, use the label we emitted last time. */
- if (last_var_location_insn != NULL_RTX
- && last_var_location_insn == next_real
- && last_in_cold_section_p == in_cold_section_p)
- newloc->label = last_label;
- else
+ if (last_var_location_insn == NULL_RTX
+ || last_var_location_insn != next_real
+ || last_in_cold_section_p != in_cold_section_p)
{
ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
loclabel_num++;
- newloc->label = ggc_strdup (loclabel);
+ last_label = ggc_strdup (loclabel);
+ if (!NOTE_DURING_CALL_P (loc_note))
+ last_postcall_label = NULL;
}
newloc->var_loc_note = loc_note;
newloc->next = NULL;
+ if (!NOTE_DURING_CALL_P (loc_note))
+ newloc->label = last_label;
+ else
+ {
+ if (!last_postcall_label)
+ {
+ sprintf (loclabel, "%s-1", last_label);
+ last_postcall_label = ggc_strdup (loclabel);
+ }
+ newloc->label = last_postcall_label;
+ }
+
if (cfun && in_cold_section_p)
newloc->section_label = crtl->subsections.cold_section_label;
else
newloc->section_label = text_section_label;
last_var_location_insn = next_real;
- last_label = newloc->label;
last_in_cold_section_p = in_cold_section_p;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
add_var_loc_to_decl (decl, newloc);
@@ -16964,14 +17940,14 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
}
/* A helper function for dwarf2out_finish called through
- ht_forall. Emit one queued .debug_str string. */
+ htab_traverse. Emit one queued .debug_str string. */
static int
output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
{
struct indirect_string_node *node = (struct indirect_string_node *) *h;
- if (node->form == DW_FORM_strp)
+ if (node->label && node->refcount)
{
switch_to_section (debug_str_section);
ASM_OUTPUT_LABEL (asm_out_file, node->label);
@@ -17249,6 +18225,20 @@ prune_unused_types_prune (dw_die_ref die)
} while (c != die->die_child);
}
+/* A helper function for dwarf2out_finish called through
+ htab_traverse. Clear .debug_str strings that we haven't already
+ decided to emit. */
+
+static int
+prune_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
+{
+ struct indirect_string_node *node = (struct indirect_string_node *) *h;
+
+ if (!node->label || !node->refcount)
+ htab_clear_slot (debug_str_hash, h);
+
+ return 1;
+}
/* Remove dies representing declarations that we never use. */
@@ -17279,7 +18269,9 @@ prune_unused_types (void)
prune_unused_types_mark (arange_table[i], 1);
/* Get rid of nodes that aren't marked; and update the string counts. */
- if (debug_str_hash)
+ if (debug_str_hash && debug_str_hash_forced)
+ htab_traverse (debug_str_hash, prune_indirect_string, NULL);
+ else if (debug_str_hash)
htab_empty (debug_str_hash);
prune_unused_types_prune (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
@@ -17346,6 +18338,8 @@ dwarf2out_finish (const char *filename)
dw_die_ref die = 0;
unsigned int i;
+ gen_remaining_tmpl_value_param_die_attribute ();
+
/* Add the name for the main input file now. We delayed this from
dwarf2out_init to avoid complications with PCH. */
add_name_attribute (comp_unit_die, remap_debug_filename (filename));