#include "hashtab.h"
#include "cgraph.h"
#include "input.h"
+#include "gimple.h"
+#include "tree-pass.h"
#ifdef DWARF2_DEBUGGING_INFO
static void dwarf2out_source_line (unsigned int, const char *, int, bool);
#endif
if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
return false;
- if (saved_do_cfi_asm || !eh_personality_libfunc)
+ if (saved_do_cfi_asm)
return true;
if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
return false;
static GTY(()) section *debug_ranges_section;
static GTY(()) section *debug_frame_section;
+/* Personality decl of current unit. Used only when assembler does not support
+ personality CFI. */
+static GTY(()) rtx current_unit_personality;
+
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
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;
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-/* Switch to eh_frame_section. If we don't have an eh_frame_section,
- switch to the data section instead, and write out a synthetic label
- for collect2. */
+/* Switch [BACK] to eh_frame_section. If we don't have an eh_frame_section,
+ switch to the data section instead, and write out a synthetic start label
+ for collect2 the first time around. */
static void
-switch_to_eh_frame_section (void)
+switch_to_eh_frame_section (bool back)
{
tree label;
/* We have no special eh_frame section. Put the information in
the data section and emit special labels to guide collect2. */
switch_to_section (data_section);
- label = get_file_function_name ("F");
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
- targetm.asm_out.globalize_label (asm_out_file,
- IDENTIFIER_POINTER (label));
- ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+
+ if (!back)
+ {
+ label = get_file_function_name ("F");
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ targetm.asm_out.globalize_label (asm_out_file,
+ IDENTIFIER_POINTER (label));
+ ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+ }
+ }
+}
+
+/* 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_cfi (cfi, fde, for_eh);
}
+ /* If we are to emit a ref/link from function bodies to their frame tables,
+ do it now. This is typically performed to make sure that tables
+ associated with functions are dragged with them and not discarded in
+ garbage collecting links. We need to do this on a per function basis to
+ cope with -ffunction-sections. */
+
+#ifdef ASM_OUTPUT_DWARF_TABLE_REF
+ /* Switch to the function section, emit the ref to the tables, and
+ switch *back* into the table section. */
+ switch_to_section (function_section (fde->decl));
+ ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
+ switch_to_frame_table_section (for_eh, true);
+#endif
+
/* Pad the FDE out to an address sized boundary. */
ASM_OUTPUT_ALIGN (asm_out_file,
floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
j += 2;
}
-
/* Output the call frame information used to record information
that relates to calculating the frame pointer, and records the
location of saved registers. */
int per_encoding = DW_EH_PE_absptr;
int lsda_encoding = DW_EH_PE_absptr;
int return_reg;
+ rtx personality = NULL;
int dw_cie_version;
/* Don't emit a CIE if there won't be any FDEs. */
if (flag_debug_asm)
app_enable ();
- if (for_eh)
- switch_to_eh_frame_section ();
- else
- {
- if (!debug_frame_section)
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
- switch_to_section (debug_frame_section);
- }
+ /* Switch to the proper frame section, first time. */
+ switch_to_frame_table_section (for_eh, false);
ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
augmentation[0] = 0;
augmentation_size = 0;
+
+ personality = current_unit_personality;
if (for_eh)
{
char *p;
lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
p = augmentation + 1;
- if (eh_personality_libfunc)
+ if (personality)
{
*p++ = 'P';
augmentation_size += 1 + size_of_encoded_value (per_encoding);
- assemble_external_libcall (eh_personality_libfunc);
+ assemble_external_libcall (personality);
}
if (any_lsda_needed)
{
}
/* Ug. Some platforms can't do unaligned dynamic relocations at all. */
- if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned)
+ if (personality && per_encoding == DW_EH_PE_aligned)
{
int offset = ( 4 /* Length */
+ 4 /* CIE Id */
if (augmentation[0])
{
dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
- if (eh_personality_libfunc)
+ if (personality)
{
dw2_asm_output_data (1, per_encoding, "Personality (%s)",
eh_data_format_name (per_encoding));
dw2_asm_output_encoded_addr_rtx (per_encoding,
- eh_personality_libfunc,
+ personality,
true, NULL);
}
{
int enc;
rtx ref;
+ rtx personality = get_personality_function (current_function_decl);
fprintf (asm_out_file, "\t.cfi_startproc\n");
- if (eh_personality_libfunc)
+ if (personality)
{
enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
- ref = eh_personality_libfunc;
+ ref = personality;
/* ??? The GAS support isn't entirely consistent. We have to
handle indirect support ourselves, but PC-relative is done
if (dwarf2out_do_cfi_asm ())
dwarf2out_do_cfi_startproc (false);
+ else
+ {
+ rtx personality = get_personality_function (current_function_decl);
+ if (!current_unit_personality)
+ current_unit_personality = personality;
+
+ /* We cannot keep a current personality per function as without CFI
+ asm at the point where we emit the CFI data there is no current
+ function anymore. */
+ if (personality
+ && current_unit_personality != personality)
+ sorry ("Multiple EH personalities are supported only with assemblers "
+ "supporting .cfi.personality directive.");
+ }
}
/* Output a marker (i.e. a label) for the absolute end of the generated code
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 {
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
{
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:
}
}
+#ifdef DWARF2_DEBUGGING_INFO
+/* Add a constant OFFSET to a location list. */
+
+static void
+loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
+{
+ dw_loc_list_ref d;
+ for (d = list_head; d != NULL; d = d->dw_loc_next)
+ loc_descr_plus_const (&d->expr, offset);
+}
+#endif
+
/* Return the size of a location descriptor. */
static unsigned long
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;
}
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
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:
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:
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
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 ();
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;
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;
/* 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,
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 *);
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, bool, dw_die_ref);
+static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
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);
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_from_tree_1 (tree, int);
-static dw_loc_descr_ref loc_descriptor_from_tree (tree);
+static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
+ enum var_init_status);
+static dw_loc_list_ref loc_list_from_tree (tree, int);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
static tree field_type (const_tree);
static unsigned int simple_type_align_in_bits (const_tree);
static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree);
static HOST_WIDE_INT field_byte_offset (const_tree);
static void add_AT_location_description (dw_die_ref, enum dwarf_attribute,
- dw_loc_descr_ref);
+ dw_loc_list_ref);
static void add_data_member_location_attribute (dw_die_ref, tree);
-static void add_const_value_attribute (dw_die_ref, rtx);
+static bool 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,
+static bool 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 bool tree_add_const_value_attribute (dw_die_ref, tree);
+static bool 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);
static void gen_entry_point_die (tree, dw_die_ref);
#endif
static dw_die_ref gen_enumeration_type_die (tree, dw_die_ref);
-static dw_die_ref gen_formal_parameter_die (tree, tree, dw_die_ref);
+static dw_die_ref gen_formal_parameter_die (tree, tree, bool, dw_die_ref);
+static dw_die_ref gen_formal_parameter_pack_die (tree, tree, dw_die_ref, tree*);
static void gen_unspecified_parameters_die (tree, dw_die_ref);
static void gen_formal_types_die (tree, dw_die_ref);
static void gen_subprogram_die (tree, dw_die_ref);
static void gen_block_die (tree, dw_die_ref, int);
static void decls_for_scope (tree, dw_die_ref, int);
static int is_redundant_typedef (const_tree);
+static inline dw_die_ref get_context_die (tree);
static void gen_namespace_die (tree, dw_die_ref);
static void gen_decl_die (tree, tree, dw_die_ref);
static dw_die_ref force_decl_die (tree);
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 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 *,
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
return "DW_TAG_condition";
case DW_TAG_shared_type:
return "DW_TAG_shared_type";
+ case DW_TAG_template_parameter_pack:
+ return "DW_TAG_template_parameter_pack";
+ case DW_TAG_formal_parameter_pack:
+ return "DW_TAG_formal_parameter_pack";
case DW_TAG_MIPS_loop:
return "DW_TAG_MIPS_loop";
case DW_TAG_format_label:
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>";
}
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";
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);
}
(const char *)x2) == 0;
}
+/* Add STR to the indirect string hash table. */
+
static struct indirect_string_node *
find_AT_string (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)
{
{
struct indirect_string_node *node;
unsigned int len;
- char label[32];
gcc_assert (a && AT_class (a) == dw_val_class_str);
&& (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;
}
static inline var_loc_list *
lookup_decl_loc (const_tree decl)
{
+ if (!decl_loc_table)
+ return NULL;
return (var_loc_list *)
htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
}
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");
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);
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)
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
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;
case REAL_TYPE:
if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
- encoding = DW_ATE_decimal_float;
+ {
+ if (dwarf_version >= 3 || !dwarf_strict)
+ encoding = DW_ATE_decimal_float;
+ else
+ encoding = DW_ATE_lo_user;
+ }
else
encoding = DW_ATE_float;
break;
case FIXED_POINT_TYPE:
- if (TYPE_UNSIGNED (type))
+ if (!(dwarf_version >= 3 || !dwarf_strict))
+ encoding = DW_ATE_lo_user;
+ else if (TYPE_UNSIGNED (type))
encoding = DW_ATE_unsigned_fixed;
else
encoding = DW_ATE_signed_fixed;
return mod_type_die;
}
+/* 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, arg_pack_elems;
+
+ parm = TREE_VEC_ELT (parms, i);
+ arg = TREE_VEC_ELT (args, i);
+ arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg);
+ gcc_assert (parm && TREE_VALUE (parm) && arg);
+
+ if (parm && TREE_VALUE (parm) && arg)
+ {
+ /* If PARM represents a template parameter pack,
+ emit a DW_TAG_template_parameter_pack DIE, followed
+ by DW_TAG_template_*_parameter DIEs for the argument
+ pack elements of ARG. Note that ARG would then be
+ an argument pack. */
+ if (arg_pack_elems)
+ template_parameter_pack_die (TREE_VALUE (parm),
+ arg_pack_elems,
+ die);
+ else
+ generic_parameter_die (TREE_VALUE (parm), arg,
+ true /* Emit DW_AT_name */, die);
+ }
+ }
+}
+
+/* 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.
+ EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the
+ name of the PARM.
+ PARENT_DIE is the parent DIE which the new created DIE should be added to,
+ as a child node. */
+
+static dw_die_ref
+generic_parameter_die (tree parm, tree arg,
+ bool emit_name_p,
+ dw_die_ref parent_die)
+{
+ 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 PARM is a generic parameter pack, it means we are
+ emitting debug info for a template argument pack element.
+ In other terms, ARG is a template argument pack element.
+ In that case, we don't emit any DW_AT_name attribute for
+ the die. */
+ if (emit_name_p)
+ {
+ 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;
+}
+
+/* Generate and return a DW_TAG_template_parameter_pack DIE representing.
+ PARM_PACK must be a template parameter pack. The returned DIE
+ will be child DIE of PARENT_DIE. */
+
+static dw_die_ref
+template_parameter_pack_die (tree parm_pack,
+ tree parm_pack_args,
+ dw_die_ref parent_die)
+{
+ dw_die_ref die;
+ int j;
+
+ gcc_assert (parent_die
+ && parm_pack
+ && DECL_NAME (parm_pack));
+
+ die = new_die (DW_TAG_template_parameter_pack, parent_die, parm_pack);
+ add_AT_string (die, DW_AT_name, IDENTIFIER_POINTER (DECL_NAME (parm_pack)));
+
+ for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++)
+ generic_parameter_die (parm_pack,
+ TREE_VEC_ELT (parm_pack_args, j),
+ false /* Don't emit DW_AT_name */,
+ die);
+ return die;
+}
+
/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
an enumerated type. */
#endif
#ifdef DWARF2_DEBUGGING_INFO
+/* Return loc description representing "address" of integer value.
+ This can appear only as toplevel expression. */
+
+static dw_loc_descr_ref
+address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
+{
+ int litsize;
+ dw_loc_descr_ref loc_result = NULL;
+
+ if (!(dwarf_version >= 4 || !dwarf_strict))
+ return NULL;
+
+ 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 ((int) DWARF2_ADDR_SIZE >= size
+ && litsize + 1 + 1 + 1 < 1 + 1 + size)
+ {
+ 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, size);
+ return loc_result;
+ }
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ size, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+ loc_result->dw_loc_oprnd2.v.val_int = i;
+ return loc_result;
+}
/* Return a location descriptor that designates a base+offset location. */
&& CONST_INT_P (XEXP (rtl, 1)))));
}
-/* Return a descriptor that describes the concatenation of N locations
- used to form the address of a memory location. */
-
-static dw_loc_descr_ref
-concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
- enum var_init_status initialized)
-{
- unsigned int i;
- dw_loc_descr_ref cc_loc_result = NULL;
- unsigned int n = XVECLEN (concatn, 0);
-
- for (i = 0; i < n; ++i)
- {
- dw_loc_descr_ref ref;
- rtx x = XVECEXP (concatn, 0, i);
-
- ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED);
- if (ref == NULL)
- return NULL;
-
- add_loc_descr (&cc_loc_result, ref);
- add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
- }
-
- if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
-
- return cc_loc_result;
-}
-
/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
failed. */
|| !DECL_THREAD_LOCAL_P (base))
return NULL;
- loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2);
+ loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 2);
if (loc_result == NULL)
return NULL;
return loc_result;
}
+/* Output debug info about reason why we failed to expand expression as dwarf
+ expression. */
+
+static void
+expansion_failed (tree expr, rtx rtl, char const *reason)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Failed to expand as dwarf: ");
+ if (expr)
+ print_generic_expr (dump_file, expr, dump_flags);
+ if (rtl)
+ {
+ fprintf (dump_file, "\n");
+ print_rtl (dump_file, rtl);
+ }
+ fprintf (dump_file, "\nReason: %s\n", reason);
+ }
+}
+
/* The following routine converts the RTL for a variable or parameter
(resident in memory) into an equivalent Dwarf representation of a
mechanism for getting the address of that same variable onto the top of a
{
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
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
rtl = XEXP (rtl, 0);
-
- /* ... fall through ... */
+ if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE)
+ break;
+ mem_loc_result = mem_loc_descriptor (rtl, mode, initialized);
+ break;
case REG:
/* Whenever a register number forms a part of the description of the
}
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);
FIXME: might try to use DW_OP_const_value here, though
DW_OP_piece complicates it. */
if (!marked)
- return 0;
- }
-
+ {
+ expansion_failed (NULL_TREE, rtl,
+ "Constant was removed from constant pool.\n");
+ 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;
+ }
+
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;
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
+ case CONCAT:
+ case CONCATN:
+ case VAR_LOCATION:
+ expansion_failed (NULL_TREE, rtl,
+ "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
+ gcc_unreachable ();
+ return 0;
+
case PRE_MODIFY:
/* Extract the PLUS expression nested inside and fall into
PLUS code below. */
/* 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;
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;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, op1);
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ case ABS:
+ op = DW_OP_abs;
+ goto do_unop;
+
+ 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));
break;
- case CONCATN:
- mem_loc_result = concatn_mem_loc_descriptor (rtl, mode,
- VAR_INIT_STATUS_INITIALIZED);
+ 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:
+ case HIGH:
/* 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:
+ /* These can't easily be tracked, see PR41404. */
+ break;
+
default:
+#ifdef ENABLE_CHECKING
+ print_rtl (stderr, rtl);
gcc_unreachable ();
+#else
+ break;
+#endif
}
if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
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;
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;
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;
up an entire register. For now, just assume that it is
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
- rtl = SUBREG_REG (rtl);
-
- /* ... fall through ... */
+ loc_result = loc_descriptor (SUBREG_REG (rtl), mode, initialized);
+ break;
case REG:
loc_result = reg_loc_descriptor (rtl, initialized);
break;
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+ break;
+
case MEM:
loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
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;
}
/* 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));
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);
}
break;
+ case CONST_INT:
+ if (mode != VOIDmode && mode != BLKmode)
+ loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
+ INTVAL (rtl));
+ break;
+
+ case CONST_DOUBLE:
+ if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
+ {
+ /* 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 || !dwarf_strict))
+ {
+ 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 || !dwarf_strict))
+ {
+ 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 || !dwarf_strict))
+ {
+ /* 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;
}
-/* Similar, but generate the descriptor from trees instead of rtl. This comes
- up particularly with variable length arrays. WANT_ADDRESS is 2 if this is
- a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a
- top-level invocation, and we require the address of LOC; is 0 if we require
- the value of LOC. */
+/* We need to figure out what section we should use as the base for the
+ address ranges where a given location is valid.
+ 1. If this particular DECL has a section associated with it, use that.
+ 2. If this function has a section associated with it, use that.
+ 3. Otherwise, use the text section.
+ XXX: If you split a variable across multiple sections, we won't notice. */
+
+static const char *
+secname_for_decl (const_tree decl)
+{
+ const char *secname;
+
+ if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
+ {
+ tree sectree = DECL_SECTION_NAME (decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
+ {
+ tree sectree = DECL_SECTION_NAME (current_function_decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (cfun && in_cold_section_p)
+ secname = crtl->subsections.cold_section_label;
+ else
+ secname = text_section_label;
+
+ return secname;
+}
+
+/* Return true when DECL_BY_REFERENCE is defined and set for DECL. */
+
+static bool
+decl_by_reference_p (tree decl)
+{
+ return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && DECL_BY_REFERENCE (decl));
+}
+
+
+/* Dereference a location expression LOC if DECL is passed by invisible
+ reference. */
+
+static dw_loc_descr_ref
+loc_by_reference (dw_loc_descr_ref loc, tree decl)
+{
+ HOST_WIDE_INT size;
+ enum dwarf_location_atom op;
+
+ if (loc == NULL)
+ return NULL;
+
+ if (!decl_by_reference_p (decl))
+ return loc;
+
+ /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead
+ change it into corresponding DW_OP_breg{0...31,x} 0. Then the
+ location expression is considered to be address of a memory location,
+ rather than the register itself. */
+ if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31)
+ || loc->dw_loc_opc == DW_OP_regx)
+ && (loc->dw_loc_next == NULL
+ || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit
+ && loc->dw_loc_next->dw_loc_next == NULL)))
+ {
+ if (loc->dw_loc_opc == DW_OP_regx)
+ {
+ loc->dw_loc_opc = DW_OP_bregx;
+ loc->dw_loc_oprnd2.v.val_int = 0;
+ }
+ else
+ {
+ loc->dw_loc_opc
+ = (enum dwarf_location_atom)
+ (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0));
+ loc->dw_loc_oprnd1.v.val_int = 0;
+ }
+ return loc;
+ }
+
+ size = int_size_in_bytes (TREE_TYPE (decl));
+ if (size > DWARF2_ADDR_SIZE || size == -1)
+ return 0;
+ else if (size == DWARF2_ADDR_SIZE)
+ op = DW_OP_deref;
+ else
+ op = DW_OP_deref_size;
+ add_loc_descr (&loc, new_loc_descr (op, size, 0));
+ return loc;
+}
+
+/* Return single element location list containing loc descr REF. */
+
+static dw_loc_list_ref
+single_element_loc_list (dw_loc_descr_ref ref)
+{
+ return new_loc_list (ref, NULL, NULL, NULL, 0);
+}
+
+/* Return dwarf representation of location list representing for
+ LOC_LIST of DECL. */
+
+static dw_loc_list_ref
+dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel)
+{
+ const char *endname, *secname;
+ dw_loc_list_ref list;
+ rtx varloc;
+ enum var_init_status initialized;
+ struct var_loc_node *node;
+ dw_loc_descr_ref descr;
+ char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ bool by_reference = decl_by_reference_p (decl);
+
+ /* Now that we know what section we are using for a base,
+ actually construct the list of locations.
+ The first location information is what is passed to the
+ function that creates the location list, and the remaining
+ locations just get added on to that list.
+ Note that we only know the start address for a location
+ (IE location changes), so to build the range, we use
+ the range [current location start, next location start].
+ This means we have to special case the last node, and generate
+ a range of [last location start, end of function label]. */
+
+ node = loc_list->first;
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ secname = secname_for_decl (decl);
+
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
+ initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+ else
+ initialized = VAR_INIT_STATUS_INITIALIZED;
+
+ if (!toplevel || by_reference)
+ {
+ gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+ /* Single part. */
+ if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
+ descr = loc_by_reference (mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0),
+ TYPE_MODE (TREE_TYPE (decl)),
+ initialized),
+ decl);
+ else
+ descr = NULL;
+ }
+ else
+ descr = loc_descriptor (varloc, DECL_MODE (decl), initialized);
+
+ if (loc_list && loc_list->first != loc_list->last)
+ list = new_loc_list (descr, node->label, node->next->label, secname, 1);
+ else
+ return single_element_loc_list (descr);
+ node = node->next;
+
+ if (!node)
+ return NULL;
+
+ for (; node->next; node = node->next)
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ /* The variable has a location between NODE->LABEL and
+ NODE->NEXT->LABEL. */
+ enum var_init_status initialized =
+ NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ if (!toplevel || by_reference)
+ {
+ gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+ /* Single part. */
+ if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
+ descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0),
+ TYPE_MODE (TREE_TYPE (decl)), initialized);
+ else
+ descr = NULL;
+ descr = loc_by_reference (descr, decl);
+ }
+ else
+ descr = loc_descriptor (varloc, DECL_MODE (decl), initialized);
+ add_loc_descr_to_loc_list (&list, descr,
+ node->label, node->next->label, secname);
+ }
+
+ /* If the variable has a location at the last label
+ it keeps its location until the end of function. */
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ enum var_init_status initialized =
+ NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+
+ if (!current_function_decl)
+ endname = text_end_label;
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ endname = ggc_strdup (label_id);
+ }
+
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ if (!toplevel || by_reference)
+ {
+ gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
+ /* Single part. */
+ if (GET_CODE (XEXP (varloc, 1)) != PARALLEL)
+ descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0),
+ TYPE_MODE (TREE_TYPE (decl)), initialized);
+ else
+ descr = NULL;
+ descr = loc_by_reference (descr, decl);
+ }
+ else
+ descr = loc_descriptor (varloc, DECL_MODE (decl), initialized);
+ add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname);
+ }
+ return list;
+}
+
+/* Return if the loc_list has only single element and thus can be represented
+ as location description. */
+
+static bool
+single_element_loc_list_p (dw_loc_list_ref list)
+{
+ return (!list->dw_loc_next && !list->begin && !list->end);
+}
+
+/* To each location in list LIST add loc descr REF. */
+
+static void
+add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
+{
+ dw_loc_descr_ref copy;
+ add_loc_descr (&list->expr, ref);
+ list = list->dw_loc_next;
+ while (list)
+ {
+ copy = GGC_CNEW (dw_loc_descr_node);
+ memcpy (copy, ref, sizeof (dw_loc_descr_node));
+ add_loc_descr (&list->expr, copy);
+ while (copy->dw_loc_next)
+ {
+ dw_loc_descr_ref new_copy = GGC_CNEW (dw_loc_descr_node);
+ memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
+ copy->dw_loc_next = new_copy;
+ copy = new_copy;
+ }
+ list = list->dw_loc_next;
+ }
+}
+
+/* Given two lists RET and LIST
+ produce location list that is result of adding expression in LIST
+ to expression in RET on each possition in program.
+ Might be destructive on both RET and LIST.
+
+ TODO: We handle only simple cases of RET or LIST having at most one
+ element. General case would inolve sorting the lists in program order
+ and merging them that will need some additional work.
+ Adding that will improve quality of debug info especially for SRA-ed
+ structures. */
+
+static void
+add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
+{
+ if (!list)
+ return;
+ if (!*ret)
+ {
+ *ret = list;
+ return;
+ }
+ if (!list->dw_loc_next)
+ {
+ add_loc_descr_to_each (*ret, list->expr);
+ return;
+ }
+ if (!(*ret)->dw_loc_next)
+ {
+ add_loc_descr_to_each (list, (*ret)->expr);
+ *ret = list;
+ return;
+ }
+ expansion_failed (NULL_TREE, NULL_RTX,
+ "Don't know how to merge two non-trivial"
+ " location lists.\n");
+ *ret = NULL;
+ return;
+}
+
+/* LOC is constant expression. Try a luck, look it up in constant
+ pool and return its loc_descr of its address. */
static dw_loc_descr_ref
-loc_descriptor_from_tree_1 (tree loc, int want_address)
+cst_pool_loc_descr (tree loc)
{
- dw_loc_descr_ref ret, ret1;
+ /* Get an RTL for this, if something has been emitted. */
+ rtx rtl = lookup_constant_def (loc);
+ enum machine_mode mode;
+
+ if (!rtl || !MEM_P (rtl))
+ {
+ gcc_assert (!rtl);
+ return 0;
+ }
+ gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
+
+ /* TODO: We might get more coverage if we was actually delaying expansion
+ of all expressions till end of compilation when constant pools are fully
+ populated. */
+ if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
+ {
+ expansion_failed (loc, NULL_RTX,
+ "CST value in contant pool but not marked.");
+ return 0;
+ }
+ mode = GET_MODE (rtl);
+ rtl = XEXP (rtl, 0);
+ return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+}
+
+/* Return dw_loc_list representing address of addr_expr LOC
+ by looking for innder INDIRECT_REF expression and turing it
+ into simple arithmetics. */
+
+static dw_loc_list_ref
+loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+{
+ tree obj, offset;
+ HOST_WIDE_INT bitsize, bitpos, bytepos;
+ enum machine_mode mode;
+ int volatilep;
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+ dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
+
+ obj = get_inner_reference (TREE_OPERAND (loc, 0),
+ &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ STRIP_NOPS (obj);
+ if (bitpos % BITS_PER_UNIT)
+ {
+ expansion_failed (loc, NULL_RTX, "bitfield access");
+ return 0;
+ }
+ if (!INDIRECT_REF_P (obj))
+ {
+ expansion_failed (obj,
+ NULL_RTX, "no indirect ref in inner refrence");
+ return 0;
+ }
+ if (!offset && !bitpos)
+ list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+ else if (toplev
+ && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
+ && (dwarf_version >= 4 || !dwarf_strict))
+ {
+ list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
+ if (!list_ret)
+ return 0;
+ if (offset)
+ {
+ /* Variable offset. */
+ list_ret1 = loc_list_from_tree (offset, 0);
+ if (list_ret1 == 0)
+ return 0;
+ add_loc_list (&list_ret, list_ret1);
+ if (!list_ret)
+ return 0;
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_plus, 0, 0));
+ }
+ bytepos = bitpos / BITS_PER_UNIT;
+ if (bytepos > 0)
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_plus_uconst,
+ bytepos, 0));
+ else if (bytepos < 0)
+ loc_list_plus_const (list_ret, bytepos);
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_piece,
+ int_size_in_bytes (TREE_TYPE
+ (loc)),
+ 0));
+ }
+ return list_ret;
+}
+
+
+/* Generate Dwarf location list representing LOC.
+ If WANT_ADDRESS is false, expression computing LOC will be computed
+ If WANT_ADDRESS is 1, expression computing address of LOC will be returned
+ if WANT_ADDRESS is 2, expression computing address useable in location
+ will be returned (i.e. DW_OP_reg can be used
+ to refer to register values)
+ TODO: Dwarf4 adds types to the stack machine that ought to be used here
+ DW_OP_stack_value will help in cases where we fail to find address of the
+ expression.
+ */
+
+static dw_loc_list_ref
+loc_list_from_tree (tree loc, int want_address)
+{
+ dw_loc_descr_ref ret = NULL, ret1 = NULL;
+ dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
int have_address = 0;
enum dwarf_location_atom op;
switch (TREE_CODE (loc))
{
case ERROR_MARK:
+ expansion_failed (loc, NULL_RTX, "ERROR_MARK");
return 0;
case PLACEHOLDER_EXPR:
position of other fields. We don't try to encode this here. The
only user of this is Ada, which encodes the needed information using
the names of types. */
+ expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
return 0;
case CALL_EXPR:
+ expansion_failed (loc, NULL_RTX, "CALL_EXPR");
+ /* There are no opcodes for these operations. */
return 0;
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
+ expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT");
/* There are no opcodes for these operations. */
return 0;
case ADDR_EXPR:
- /* If we already want an address, there's nothing we can do. */
+ /* If we already want an address, see if there is INDIRECT_REF inside
+ e.g. for &this->field. */
if (want_address)
- return 0;
-
- /* Otherwise, process the argument and look for the address. */
- return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
+ {
+ list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
+ (loc, want_address == 2);
+ if (list_ret)
+ have_address = 1;
+ else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
+ && (ret = cst_pool_loc_descr (loc)))
+ have_address = 1;
+ }
+ /* Otherwise, process the argument and look for the address. */
+ if (!list_ret && !ret)
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
+ else
+ {
+ if (want_address)
+ expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
+ return NULL;
+ }
+ break;
case VAR_DECL:
if (DECL_THREAD_LOCAL_P (loc))
if (targetm.have_tls)
{
/* If this is not defined, we have no way to emit the
- data. */
+ data. */
if (!targetm.asm_out.output_dwarf_dtprel)
return 0;
}
else
{
- if (!targetm.emutls.debug_form_tls_address)
+ if (!targetm.emutls.debug_form_tls_address
+ || !(dwarf_version >= 3 || !dwarf_strict))
return 0;
loc = emutls_decl (loc);
first_op = DW_OP_addr;
case PARM_DECL:
if (DECL_HAS_VALUE_EXPR_P (loc))
- return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc),
- want_address);
+ return loc_list_from_tree (DECL_VALUE_EXPR (loc),
+ want_address);
/* FALLTHRU */
case RESULT_DECL:
case FUNCTION_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
+ var_loc_list *loc_list = lookup_decl_loc (loc);
- if (rtl == NULL_RTX)
- return 0;
+ if (loc_list && loc_list->first
+ && (list_ret = dw_loc_list (loc_list, loc, want_address == 2)))
+ have_address = 1;
+ else if (rtl == NULL_RTX)
+ {
+ expansion_failed (loc, NULL_RTX, "DECL has no RTL");
+ return 0;
+ }
else if (CONST_INT_P (rtl))
{
HOST_WIDE_INT val = INTVAL (rtl);
ret = int_loc_descriptor (val);
}
else if (GET_CODE (rtl) == CONST_STRING)
- return 0;
+ {
+ expansion_failed (loc, NULL_RTX, "CONST_STRING");
+ return 0;
+ }
else if (CONSTANT_P (rtl))
{
ret = new_loc_descr (DW_OP_addr, 0, 0);
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
-
- mode = GET_MODE (rtl);
- if (MEM_P (rtl))
{
- rtl = XEXP (rtl, 0);
+ ret = loc_descriptor (rtl, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
have_address = 1;
}
- ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+ else
+ {
+ mode = GET_MODE (rtl);
+ if (MEM_P (rtl))
+ {
+ rtl = XEXP (rtl, 0);
+ have_address = 1;
+ }
+ ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+ }
+ if (!ret)
+ expansion_failed (loc, rtl,
+ "failed to produce loc descriptor for rtl");
}
}
break;
case INDIRECT_REF:
- ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ case ALIGN_INDIRECT_REF:
+ case MISALIGNED_INDIRECT_REF:
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
have_address = 1;
break;
case COMPOUND_EXPR:
- return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address);
+ return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address);
CASE_CONVERT:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
case MODIFY_EXPR:
- return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
+ return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address);
case COMPONENT_REF:
case BIT_FIELD_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep, false);
- if (obj == loc)
- return 0;
+ gcc_assert (obj != loc);
- ret = loc_descriptor_from_tree_1 (obj, 1);
- if (ret == 0
- || bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
+ list_ret = loc_list_from_tree (obj,
+ want_address == 2
+ && !bitpos && !offset ? 2 : 1);
+ /* TODO: We can extract value of the small expression via shifting even
+ for nonzero bitpos. */
+ if (list_ret == 0)
return 0;
+ if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
+ {
+ expansion_failed (loc, NULL_RTX,
+ "bitfield access");
+ return 0;
+ }
if (offset != NULL_TREE)
{
/* Variable offset. */
- ret1 = loc_descriptor_from_tree_1 (offset, 0);
- if (ret1 == 0)
+ list_ret1 = loc_list_from_tree (offset, 0);
+ if (list_ret1 == 0)
return 0;
- add_loc_descr (&ret, ret1);
- add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+ add_loc_list (&list_ret, list_ret1);
+ if (!list_ret)
+ return 0;
+ add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0));
}
bytepos = bitpos / BITS_PER_UNIT;
- loc_descr_plus_const (&ret, bytepos);
+ if (bytepos > 0)
+ add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
+ else if (bytepos < 0)
+ loc_list_plus_const (list_ret, bytepos);
have_address = 1;
break;
}
case INTEGER_CST:
- if (host_integerp (loc, 0))
+ if ((want_address || !host_integerp (loc, 0))
+ && (ret = cst_pool_loc_descr (loc)))
+ have_address = 1;
+ else if (want_address == 2
+ && host_integerp (loc, 0)
+ && (ret = address_of_int_loc_descriptor
+ (int_size_in_bytes (TREE_TYPE (loc)),
+ tree_low_cst (loc, 0))))
+ have_address = 1;
+ else if (host_integerp (loc, 0))
ret = int_loc_descriptor (tree_low_cst (loc, 0));
else
- return 0;
+ {
+ expansion_failed (loc, NULL_RTX,
+ "Integer operand is not host integer");
+ return 0;
+ }
break;
case CONSTRUCTOR:
- {
- /* Get an RTL for this, if something has been emitted. */
- rtx rtl = lookup_constant_def (loc);
- enum machine_mode mode;
-
- if (!rtl || !MEM_P (rtl))
- return 0;
- mode = GET_MODE (rtl);
- rtl = XEXP (rtl, 0);
- ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+ case REAL_CST:
+ case STRING_CST:
+ case COMPLEX_CST:
+ if ((ret = cst_pool_loc_descr (loc)))
have_address = 1;
- break;
- }
+ else
+ /* We can construct small constants here using int_loc_descriptor. */
+ expansion_failed (loc, NULL_RTX,
+ "constructor or constant not in constant pool");
+ break;
case TRUTH_AND_EXPR:
case TRUTH_ANDIF_EXPR:
if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
&& host_integerp (TREE_OPERAND (loc, 1), 0))
{
- ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
- if (ret == 0)
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ if (list_ret == 0)
return 0;
- loc_descr_plus_const (&ret, tree_low_cst (TREE_OPERAND (loc, 1), 0));
+ loc_list_plus_const (list_ret, tree_low_cst (TREE_OPERAND (loc, 1), 0));
break;
}
goto do_binop;
do_binop:
- ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
- ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
- if (ret == 0 || ret1 == 0)
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+ if (list_ret == 0 || list_ret1 == 0)
return 0;
- add_loc_descr (&ret, ret1);
- add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+ add_loc_list (&list_ret, list_ret1);
+ if (list_ret == 0)
+ return 0;
+ add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
break;
case TRUTH_NOT_EXPR:
goto do_unop;
do_unop:
- ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
- if (ret == 0)
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ if (list_ret == 0)
return 0;
- add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+ add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
break;
case MIN_EXPR:
case COND_EXPR:
{
dw_loc_descr_ref lhs
- = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
- dw_loc_descr_ref rhs
- = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0);
+ = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+ dw_loc_list_ref rhs
+ = loc_list_from_tree (TREE_OPERAND (loc, 2), 0);
dw_loc_descr_ref bra_node, jump_node, tmp;
- ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
- if (ret == 0 || lhs == 0 || rhs == 0)
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ if (list_ret == 0 || lhs == 0 || rhs == 0)
return 0;
bra_node = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&ret, bra_node);
+ add_loc_descr_to_each (list_ret, bra_node);
- add_loc_descr (&ret, rhs);
+ add_loc_list (&list_ret, rhs);
jump_node = new_loc_descr (DW_OP_skip, 0, 0);
- add_loc_descr (&ret, jump_node);
+ add_loc_descr_to_each (list_ret, jump_node);
- add_loc_descr (&ret, lhs);
+ add_loc_descr_to_each (list_ret, lhs);
bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
bra_node->dw_loc_oprnd1.v.val_loc = lhs;
/* ??? Need a node to point the skip at. Use a nop. */
tmp = new_loc_descr (DW_OP_nop, 0, 0);
- add_loc_descr (&ret, tmp);
+ add_loc_descr_to_each (list_ret, tmp);
jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
jump_node->dw_loc_oprnd1.v.val_loc = tmp;
}
up, for instance, with the C STMT_EXPR. */
if ((unsigned int) TREE_CODE (loc)
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
- return 0;
+ {
+ expansion_failed (loc, NULL_RTX,
+ "language specific tree node");
+ return 0;
+ }
#ifdef ENABLE_CHECKING
/* Otherwise this is a generic code; we should just lists all of
#endif
}
+ if (!ret && !list_ret)
+ return 0;
+
+ if (want_address == 2 && !have_address
+ && (dwarf_version >= 4 || !dwarf_strict))
+ {
+ if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+ {
+ expansion_failed (loc, NULL_RTX,
+ "DWARF address size mismatch");
+ return 0;
+ }
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_piece,
+ int_size_in_bytes (TREE_TYPE
+ (loc)),
+ 0));
+ have_address = 1;
+ }
/* Show if we can't fill the request for an address. */
if (want_address && !have_address)
- return 0;
+ {
+ expansion_failed (loc, NULL_RTX,
+ "Want address and only have value");
+ return 0;
+ }
+
+ gcc_assert (!ret || !list_ret);
/* If we've got an address and don't want one, dereference. */
- if (!want_address && have_address && ret)
+ if (!want_address && have_address)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
if (size > DWARF2_ADDR_SIZE || size == -1)
- return 0;
+ {
+ expansion_failed (loc, NULL_RTX,
+ "DWARF address size mismatch");
+ return 0;
+ }
else if (size == DWARF2_ADDR_SIZE)
op = DW_OP_deref;
else
op = DW_OP_deref_size;
- add_loc_descr (&ret, new_loc_descr (op, size, 0));
+ if (ret)
+ add_loc_descr (&ret, new_loc_descr (op, size, 0));
+ else
+ add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
}
+ if (ret)
+ list_ret = single_element_loc_list (ret);
- return ret;
+ return list_ret;
}
-static inline dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc)
+/* Same as above but return only single location expression. */
+static dw_loc_descr_ref
+loc_descriptor_from_tree (tree loc, int want_address)
{
- return loc_descriptor_from_tree_1 (loc, 2);
+ dw_loc_list_ref ret = loc_list_from_tree (loc, want_address);
+ if (!ret)
+ return NULL;
+ if (ret->dw_loc_next)
+ {
+ expansion_failed (loc, NULL_RTX,
+ "Location list where only loc descriptor needed");
+ return NULL;
+ }
+ return ret->expr;
}
/* Given a value, round it up to the lowest multiple of `boundary'
field_size_tree = DECL_SIZE (decl);
/* The size could be unspecified if there was an error, or for
- a flexible array member. */
+ a flexible array member. */
if (!field_size_tree)
- field_size_tree = bitsize_zero_node;
+ field_size_tree = bitsize_zero_node;
/* If the size of the field is not constant, use the type size. */
if (host_integerp (field_size_tree, 1))
static inline void
add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
- dw_loc_descr_ref descr)
+ dw_loc_list_ref descr)
{
- if (descr != 0)
- add_AT_loc (die, attr_kind, descr);
+ if (descr == 0)
+ return;
+ if (single_element_loc_list_p (descr))
+ add_AT_loc (die, attr_kind, descr->expr);
+ else
+ add_AT_loc_list (die, attr_kind, descr);
}
/* Attach the specialized form of location attribute used for data members of
to an inlined function. They can also arise in C++ where declared
constants do not necessarily get memory "homes". */
-static void
+static bool
add_const_value_attribute (dw_die_ref die, rtx rtl)
{
switch (GET_CODE (rtl))
else
add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
}
- break;
+ return true;
case CONST_DOUBLE:
/* Note that a CONST_DOUBLE rtx could represent either an integer or a
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;
+ return true;
case CONST_VECTOR:
{
add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
}
- break;
+ return true;
case CONST_STRING:
add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
- break;
+ return true;
+ case CONST:
+ if (CONSTANT_P (XEXP (rtl, 0)))
+ {
+ add_const_value_attribute (die, XEXP (rtl, 0));
+ return true;
+ }
+ /* FALLTHROUGH */
case SYMBOL_REF:
+ if (GET_CODE (rtl) == SYMBOL_REF
+ && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
+ return false;
case LABEL_REF:
- case CONST:
add_AT_addr (die, DW_AT_const_value, rtl);
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
- break;
+ return true;
case PLUS:
/* In cases where an inlined instance of an inline function is passed
*value* which the artificial local variable always has during its
lifetime. We currently have no way to represent such quasi-constant
values in Dwarf, so for now we just punt and generate nothing. */
- break;
+ return false;
default:
/* No other kinds of rtx should be possible here. */
gcc_unreachable ();
}
-
+ return false;
}
/* Determine whether the evaluation of EXPR references any variables
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))
return rtl;
}
-/* We need to figure out what section we should use as the base for the
- address ranges where a given location is valid.
- 1. If this particular DECL has a section associated with it, use that.
- 2. If this function has a section associated with it, use that.
- 3. Otherwise, use the text section.
- XXX: If you split a variable across multiple sections, we won't notice. */
-
-static const char *
-secname_for_decl (const_tree decl)
-{
- const char *secname;
-
- if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
- {
- tree sectree = DECL_SECTION_NAME (decl);
- secname = TREE_STRING_POINTER (sectree);
- }
- else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
- {
- tree sectree = DECL_SECTION_NAME (current_function_decl);
- secname = TREE_STRING_POINTER (sectree);
- }
- else if (cfun && in_cold_section_p)
- secname = crtl->subsections.cold_section_label;
- else
- secname = text_section_label;
-
- return secname;
-}
-
/* Check whether decl is a Fortran COMMON symbol. If not, NULL_TREE is
returned. If so, the decl for the COMMON block is returned, and the
value is the offset into the common block for the symbol. */
return cvar;
}
-/* Dereference a location expression LOC if DECL is passed by invisible
- reference. */
-
-static dw_loc_descr_ref
-loc_by_reference (dw_loc_descr_ref loc, tree decl)
-{
- HOST_WIDE_INT size;
- enum dwarf_location_atom op;
-
- if (loc == NULL)
- return NULL;
-
- if ((TREE_CODE (decl) != PARM_DECL
- && TREE_CODE (decl) != RESULT_DECL
- && TREE_CODE (decl) != VAR_DECL)
- || !DECL_BY_REFERENCE (decl))
- return loc;
-
- /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead
- change it into corresponding DW_OP_breg{0...31,x} 0. Then the
- location expression is considered to be address of a memory location,
- rather than the register itself. */
- if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31)
- || loc->dw_loc_opc == DW_OP_regx)
- && (loc->dw_loc_next == NULL
- || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit
- && loc->dw_loc_next->dw_loc_next == NULL)))
- {
- if (loc->dw_loc_opc == DW_OP_regx)
- {
- loc->dw_loc_opc = DW_OP_bregx;
- loc->dw_loc_oprnd2.v.val_int = 0;
- }
- else
- {
- loc->dw_loc_opc
- = (enum dwarf_location_atom)
- (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0));
- loc->dw_loc_oprnd1.v.val_int = 0;
- }
- return loc;
- }
-
- size = int_size_in_bytes (TREE_TYPE (decl));
- if (size > DWARF2_ADDR_SIZE || size == -1)
- return 0;
- else if (size == DWARF2_ADDR_SIZE)
- op = DW_OP_deref;
- else
- op = DW_OP_deref_size;
- add_loc_descr (&loc, new_loc_descr (op, size, 0));
- return loc;
-}
-
/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
data attribute for a variable or a parameter. We generate the
DW_AT_const_value attribute only in those cases where the given variable
pointer. This can happen for example if an actual argument in an inlined
function call evaluates to a compile-time constant address. */
-static void
+static bool
add_location_or_const_value_attribute (dw_die_ref die, tree decl,
enum dwarf_attribute attr)
{
rtx rtl;
- dw_loc_descr_ref descr;
+ dw_loc_list_ref list;
var_loc_list *loc_list;
- struct var_loc_node *node;
+
if (TREE_CODE (decl) == ERROR_MARK)
- return;
+ return false;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
- /* See if we possibly have multiple locations for this variable. */
- loc_list = lookup_decl_loc (decl);
-
- /* If it truly has multiple locations, the first and last node will
- differ. */
- if (loc_list && loc_list->first != loc_list->last)
- {
- const char *endname, *secname;
- dw_loc_list_ref list;
- rtx varloc;
- enum var_init_status initialized;
-
- /* Now that we know what section we are using for a base,
- actually construct the list of locations.
- The first location information is what is passed to the
- function that creates the location list, and the remaining
- locations just get added on to that list.
- Note that we only know the start address for a location
- (IE location changes), so to build the range, we use
- the range [current location start, next location start].
- This means we have to special case the last node, and generate
- a range of [last location start, end of function label]. */
-
- node = loc_list->first;
- varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- secname = secname_for_decl (decl);
-
- if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
- initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
- else
- initialized = VAR_INIT_STATUS_INITIALIZED;
-
- descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
- list = new_loc_list (descr, node->label, node->next->label, secname, 1);
- node = node->next;
-
- for (; node->next; node = node->next)
- if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
- {
- /* The variable has a location between NODE->LABEL and
- NODE->NEXT->LABEL. */
- 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);
- add_loc_descr_to_loc_list (&list, descr,
- node->label, node->next->label, secname);
- }
-
- /* If the variable has a location at the last label
- it keeps its location until the end of function. */
- if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
- {
- char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
- enum var_init_status initialized =
- NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-
- varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- if (!current_function_decl)
- endname = text_end_label;
- else
- {
- ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
- current_function_funcdef_no);
- endname = ggc_strdup (label_id);
- }
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
- decl);
- add_loc_descr_to_loc_list (&list, descr,
- node->label, endname, secname);
- }
-
- /* Finally, add the location list to the DIE, and we are done. */
- add_AT_loc_list (die, attr, list);
- return;
- }
-
/* Try to get some constant RTL for this decl, and use that as the value of
the location. */
rtl = rtl_for_decl_location (decl);
- if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
- {
- add_const_value_attribute (die, rtl);
- return;
- }
+ if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
+ && add_const_value_attribute (die, rtl))
+ return true;
- /* If we have tried to generate the location otherwise, and it
- didn't work out (we wouldn't be here if we did), and we have a one entry
- location list, try generating a location from that. */
- if (loc_list && loc_list->first)
+ /* See if we have single element location list that is equivalent to
+ a constant value. That way we are better to use add_const_value_attribute
+ rather than expanding constant value equivalent. */
+ loc_list = lookup_decl_loc (decl);
+ if (loc_list && loc_list->first && loc_list->first == loc_list->last)
{
enum var_init_status status;
+ struct var_loc_node *node;
+
node = loc_list->first;
status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
- descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
- if (descr)
- {
- descr = loc_by_reference (descr, decl);
- add_AT_location_description (die, attr, descr);
- return;
- }
+ 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 true;
}
-
- /* We couldn't get any rtl, so try directly generating the location
- description from the tree. */
- descr = loc_descriptor_from_tree (decl);
- if (descr)
+ list = loc_list_from_tree (decl, 2);
+ if (list)
{
- descr = loc_by_reference (descr, decl);
- add_AT_location_description (die, attr, descr);
- return;
+ add_AT_location_description (die, attr, list);
+ return true;
}
/* 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);
+ return tree_add_const_value_attribute_for_decl (die, decl);
}
/* Add VARIABLE and DIE into deferred locations list. */
}
}
-/* 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)
+static bool
+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)
- return;
+ if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
+ return false;
- 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);
+ return true;
+ }
/* If the host and target are sane, try harder. */
else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
&& initializer_constant_valid_p (init, type))
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);
+ return true;
+ }
}
}
+ return false;
+}
+
+/* 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 bool
+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 false;
+
+ if (TREE_READONLY (decl)
+ && ! TREE_THIS_VOLATILE (decl)
+ && DECL_INITIAL (decl))
+ /* OK */;
+ else
+ return false;
+
+ return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
}
/* Convert the CFI instructions for the current function into a
case RESULT_DECL:
{
dw_die_ref decl_die = lookup_decl_die (bound);
- dw_loc_descr_ref loc;
+ dw_loc_list_ref loc;
/* ??? Can this happen, or should the variable have been bound
first? Probably it can, since I imagine that we try to create
add_AT_die_ref (subrange_die, bound_attr, decl_die);
else
{
- loc = loc_descriptor_from_tree_1 (bound, 0);
+ loc = loc_list_from_tree (bound, 0);
add_AT_location_description (subrange_die, bound_attr, loc);
}
break;
evaluate the value of the array bound. */
dw_die_ref ctx, decl_die;
- dw_loc_descr_ref loc;
+ dw_loc_list_ref list;
- loc = loc_descriptor_from_tree (bound);
- if (loc == NULL)
+ list = loc_list_from_tree (bound, 2);
+ if (list == NULL)
break;
if (current_function_decl == 0)
decl_die = new_die (DW_TAG_variable, ctx, bound);
add_AT_flag (decl_die, DW_AT_artificial, 1);
add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
- add_AT_loc (decl_die, DW_AT_location, loc);
+ if (list->dw_loc_next)
+ add_AT_loc_list (decl_die, DW_AT_location, list);
+ else
+ add_AT_loc (decl_die, DW_AT_location, list->expr);
add_AT_die_ref (subrange_die, bound_attr, decl_die);
break;
&& DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
{
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
- dw_loc_descr_ref loc = loc_descriptor_from_tree (szdecl);
+ dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2);
size = int_size_in_bytes (TREE_TYPE (szdecl));
if (loc && size > 0)
{
- add_AT_loc (array_die, DW_AT_string_length, loc);
+ add_AT_location_description (array_die, DW_AT_string_length, loc);
if (size != DWARF2_ADDR_SIZE)
add_AT_unsigned (array_die, DW_AT_byte_size, size);
}
CASE_CONVERT:
return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
case VAR_DECL:
- return loc_descriptor_from_tree_1 (val, 0);
+ return loc_descriptor_from_tree (val, 0);
case INTEGER_CST:
if (host_integerp (val, 0))
return int_loc_descriptor (tree_low_cst (val, 0));
return DW_TAG_class_type;
case RECORD_IS_INTERFACE:
- return DW_TAG_interface_type;
+ if (dwarf_version >= 3 || !dwarf_strict)
+ return DW_TAG_interface_type;
+ return DW_TAG_structure_type;
default:
gcc_unreachable ();
DIE to represent a formal parameter object (or some inlining thereof). If
it's the latter, then this function is only being called to output a
DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
- argument type of some subprogram type. */
+ argument type of some subprogram type.
+ If EMIT_NAME_P is true, name and source coordinate attributes
+ are emitted. */
static dw_die_ref
-gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die)
+gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
+ dw_die_ref context_die)
{
tree node_or_origin = node ? node : origin;
dw_die_ref parm_die
else
{
tree type = TREE_TYPE (node);
- add_name_and_src_coords_attributes (parm_die, node);
- if (DECL_BY_REFERENCE (node))
+ if (emit_name_p)
+ add_name_and_src_coords_attributes (parm_die, node);
+ if (decl_by_reference_p (node))
add_type_attribute (parm_die, TREE_TYPE (type), 0, 0,
context_die);
else
return parm_die;
}
+/* Generate and return a DW_TAG_formal_parameter_pack. Also generate
+ children DW_TAG_formal_parameter DIEs representing the arguments of the
+ parameter pack.
+
+ PARM_PACK must be a function parameter pack.
+ PACK_ARG is the first argument of the parameter pack. Its TREE_CHAIN
+ must point to the subsequent arguments of the function PACK_ARG belongs to.
+ SUBR_DIE is the DIE of the function PACK_ARG belongs to.
+ If NEXT_ARG is non NULL, *NEXT_ARG is set to the function argument
+ following the last one for which a DIE was generated. */
+
+static dw_die_ref
+gen_formal_parameter_pack_die (tree parm_pack,
+ tree pack_arg,
+ dw_die_ref subr_die,
+ tree *next_arg)
+{
+ tree arg;
+ dw_die_ref parm_pack_die;
+
+ gcc_assert (parm_pack
+ && lang_hooks.function_parameter_pack_p (parm_pack)
+ && DECL_NAME (parm_pack)
+ && subr_die);
+
+ parm_pack_die = new_die (DW_TAG_formal_parameter_pack, subr_die, parm_pack);
+ add_AT_string (parm_pack_die, DW_AT_name,
+ IDENTIFIER_POINTER (DECL_NAME (parm_pack)));
+
+ for (arg = pack_arg; arg; arg = TREE_CHAIN (arg))
+ {
+ if (! lang_hooks.decls.function_parm_expanded_from_pack_p (arg,
+ parm_pack))
+ break;
+ gen_formal_parameter_die (arg, NULL,
+ false /* Don't emit name attribute. */,
+ parm_pack_die);
+ }
+ if (next_arg)
+ *next_arg = arg;
+ return parm_pack_die;
+}
+
/* Generate a special type of DIE used as a stand-in for a trailing ellipsis
at the end of an (ANSI prototyped) formal parameters list. */
break;
/* Output a (nameless) DIE to represent the formal parameter itself. */
- parm_die = gen_formal_parameter_die (formal_type, NULL, context_die);
+ parm_die = gen_formal_parameter_die (formal_type, NULL,
+ true /* Emit name attribute. */,
+ context_die);
if ((TREE_CODE (function_or_method_type) == METHOD_TYPE
&& link == first_parm_type)
|| (arg && DECL_ARTIFICIAL (arg)))
tree save_fn;
tree context;
int was_abstract = DECL_ABSTRACT (decl);
+ htab_t old_decl_loc_table;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
- htab_empty (decl_loc_table);
old_die = lookup_decl_die (decl);
if (old_die && get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
+ /* We can be called while recursively when seeing block defining inlined subroutine
+ DIE. Be sure to not clobber the outer location table nor use it or we would
+ get locations in abstract instantces. */
+ old_decl_loc_table = decl_loc_table;
+ decl_loc_table = NULL;
+
/* Be sure we've emitted the in-class declaration DIE (if any) first, so
we don't get confused by DECL_ABSTRACT. */
if (debug_info_level > DINFO_LEVEL_TERSE)
set_decl_abstract_flags (decl, 0);
current_function_decl = save_fn;
+ decl_loc_table = old_decl_loc_table;
pop_cfun ();
}
/* If this is an explicit function declaration then generate
a DW_AT_explicit attribute. */
- if (lang_hooks.decls.function_decl_explicit_p (decl))
+ if (lang_hooks.decls.function_decl_explicit_p (decl)
+ && (dwarf_version >= 3 || !dwarf_strict))
add_AT_flag (subr_die, DW_AT_explicit, 1);
/* The first time we see a member function, it is in the context of
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
- loc_descriptor_from_tree (cfun->static_chain_decl));
+ loc_list_from_tree (cfun->static_chain_decl, 2));
}
+ /* 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
else
{
/* Generate DIEs to represent all known formal parameters. */
- tree arg_decls = DECL_ARGUMENTS (decl);
- tree parm;
-
- /* When generating DIEs, generate the unspecified_parameters DIE
- instead if we come across the arg "__builtin_va_alist" */
- for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
- if (TREE_CODE (parm) == PARM_DECL)
- {
- if (DECL_NAME (parm)
- && !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
- "__builtin_va_alist"))
- gen_unspecified_parameters_die (parm, subr_die);
- else
+ tree parm = DECL_ARGUMENTS (decl);
+ tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+ tree generic_decl_parm = generic_decl
+ ? DECL_ARGUMENTS (generic_decl)
+ : NULL;
+
+ /* Now we want to walk the list of parameters of the function and
+ emit their relevant DIEs.
+
+ We consider the case of DECL being an instance of a generic function
+ as well as it being a normal function.
+
+ If DECL is an instance of a generic function we walk the
+ parameters of the generic function declaration _and_ the parameters of
+ DECL itself. This is useful because we want to emit specific DIEs for
+ function parameter packs and those are declared as part of the
+ generic function declaration. In that particular case,
+ the parameter pack yields a DW_TAG_formal_parameter_pack DIE.
+ That DIE has children DIEs representing the set of arguments
+ of the pack. Note that the set of pack arguments can be empty.
+ In that case, the DW_TAG_formal_parameter_pack DIE will not have any
+ children DIE.
+
+ Otherwise, we just consider the parameters of DECL. */
+ while (generic_decl_parm || parm)
+ {
+ if (generic_decl_parm
+ && lang_hooks.function_parameter_pack_p (generic_decl_parm))
+ gen_formal_parameter_pack_die (generic_decl_parm,
+ parm, subr_die,
+ &parm);
+ else if (parm)
+ {
gen_decl_die (parm, NULL, subr_die);
- }
+ parm = TREE_CHAIN (parm);
+ }
+
+ if (generic_decl_parm)
+ generic_decl_parm = TREE_CHAIN (generic_decl_parm);
+ }
/* Decide whether we need an unspecified_parameters DIE at the end.
There are 2 more cases to do this for: 1) the ansi ... declaration -
{
tree field;
dw_die_ref com_die;
- dw_loc_descr_ref loc;
+ dw_loc_list_ref loc;
die_node com_die_arg;
var_die = lookup_decl_die (decl_or_origin);
{
if (get_AT (var_die, DW_AT_location) == NULL)
{
- loc = loc_descriptor_from_tree (com_decl);
+ loc = loc_list_from_tree (com_decl, off ? 1 : 2);
if (loc)
{
if (off)
{
/* Optimize the common case. */
- if (loc->dw_loc_opc == DW_OP_addr
- && loc->dw_loc_next == NULL
- && GET_CODE (loc->dw_loc_oprnd1.v.val_addr)
+ if (single_element_loc_list_p (loc)
+ && loc->expr->dw_loc_opc == DW_OP_addr
+ && loc->expr->dw_loc_next == NULL
+ && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr)
== SYMBOL_REF)
- loc->dw_loc_oprnd1.v.val_addr
- = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+ loc->expr->dw_loc_oprnd1.v.val_addr
+ = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
else
- loc_descr_plus_const (&loc, off);
+ loc_list_plus_const (loc, off);
}
- add_AT_loc (var_die, DW_AT_location, loc);
+ add_AT_location_description (var_die, DW_AT_location, loc);
remove_AT (var_die, DW_AT_declaration);
}
}
com_die_arg.decl_id = DECL_UID (com_decl);
com_die_arg.die_parent = context_die;
com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
- loc = loc_descriptor_from_tree (com_decl);
+ loc = loc_list_from_tree (com_decl, 2);
if (com_die == NULL)
{
const char *cnam
add_name_and_src_coords_attributes (com_die, com_decl);
if (loc)
{
- add_AT_loc (com_die, DW_AT_location, loc);
+ add_AT_location_description (com_die, DW_AT_location, loc);
/* Avoid sharing the same loc descriptor between
DW_TAG_common_block and DW_TAG_variable. */
- loc = loc_descriptor_from_tree (com_decl);
+ loc = loc_list_from_tree (com_decl, 2);
}
else if (DECL_EXTERNAL (decl))
add_AT_flag (com_die, DW_AT_declaration, 1);
}
else if (get_AT (com_die, DW_AT_location) == NULL && loc)
{
- add_AT_loc (com_die, DW_AT_location, loc);
- loc = loc_descriptor_from_tree (com_decl);
+ add_AT_location_description (com_die, DW_AT_location, loc);
+ loc = loc_list_from_tree (com_decl, 2);
remove_AT (com_die, DW_AT_declaration);
}
var_die = new_die (DW_TAG_variable, com_die, decl);
if (off)
{
/* Optimize the common case. */
- if (loc->dw_loc_opc == DW_OP_addr
- && loc->dw_loc_next == NULL
- && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
- loc->dw_loc_oprnd1.v.val_addr
- = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+ if (single_element_loc_list_p (loc)
+ && loc->expr->dw_loc_opc == DW_OP_addr
+ && loc->expr->dw_loc_next == NULL
+ && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
+ loc->expr->dw_loc_oprnd1.v.val_addr
+ = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off);
else
- loc_descr_plus_const (&loc, off);
+ loc_list_plus_const (loc, off);
}
- add_AT_loc (var_die, DW_AT_location, loc);
+ add_AT_location_description (var_die, DW_AT_location, loc);
}
else if (DECL_EXTERNAL (decl))
add_AT_flag (var_die, DW_AT_declaration, 1);
tree type = TREE_TYPE (decl);
add_name_and_src_coords_attributes (var_die, decl);
- if ((TREE_CODE (decl) == PARM_DECL
- || TREE_CODE (decl) == RESULT_DECL
- || TREE_CODE (decl) == VAR_DECL)
- && DECL_BY_REFERENCE (decl))
+ if (decl_by_reference_p (decl))
add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die);
else
add_type_attribute (var_die, type, TREE_READONLY (decl),
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. */
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. */
{
expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
- add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
- add_AT_unsigned (die, DW_AT_call_line, s.line);
+ if (dwarf_version >= 3 || !dwarf_strict)
+ {
+ add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
+ add_AT_unsigned (die, DW_AT_call_line, s.line);
+ }
}
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (BLOCK_FRAGMENT_CHAIN (stmt))
+ if (BLOCK_FRAGMENT_CHAIN (stmt)
+ && (dwarf_version >= 3 || !dwarf_strict))
{
tree chain;
add_AT_string (die, DW_AT_producer, producer);
+ language = DW_LANG_C89;
if (strcmp (language_string, "GNU C++") == 0)
language = DW_LANG_C_plus_plus;
- else if (strcmp (language_string, "GNU Ada") == 0)
- language = DW_LANG_Ada95;
else if (strcmp (language_string, "GNU F77") == 0)
language = DW_LANG_Fortran77;
- else if (strcmp (language_string, "GNU Fortran") == 0)
- language = DW_LANG_Fortran95;
else if (strcmp (language_string, "GNU Pascal") == 0)
language = DW_LANG_Pascal83;
- else if (strcmp (language_string, "GNU Java") == 0)
- language = DW_LANG_Java;
- else if (strcmp (language_string, "GNU Objective-C") == 0)
- language = DW_LANG_ObjC;
- else if (strcmp (language_string, "GNU Objective-C++") == 0)
- language = DW_LANG_ObjC_plus_plus;
- else
- language = DW_LANG_C89;
+ else if (dwarf_version >= 3 || !dwarf_strict)
+ {
+ if (strcmp (language_string, "GNU Ada") == 0)
+ language = DW_LANG_Ada95;
+ else if (strcmp (language_string, "GNU Fortran") == 0)
+ language = DW_LANG_Fortran95;
+ else if (strcmp (language_string, "GNU Java") == 0)
+ language = DW_LANG_Java;
+ else if (strcmp (language_string, "GNU Objective-C") == 0)
+ language = DW_LANG_ObjC;
+ else if (strcmp (language_string, "GNU Objective-C++") == 0)
+ language = DW_LANG_ObjC_plus_plus;
+ }
add_AT_unsigned (die, DW_AT_language, language);
return 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)
the type description DIE we want to generate. */
if (DECL_CONTEXT (TYPE_NAME (type))
&& TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
- context_die = lookup_decl_die (DECL_CONTEXT (TYPE_NAME (type)));
+ context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
TREE_ASM_WRITTEN (type) = 1;
gen_decl_die (TYPE_NAME (type), NULL, context_die);
/* If this is an array type with hidden descriptor, handle it first. */
if (!TREE_ASM_WRITTEN (type)
&& lang_hooks.types.get_array_descr_info
- && lang_hooks.types.get_array_descr_info (type, &info))
+ && lang_hooks.types.get_array_descr_info (type, &info)
+ && (dwarf_version >= 3 || !dwarf_strict))
{
gen_descr_array_type_die (type, &info, context_die);
TREE_ASM_WRITTEN (type) = 1;
context_die = lookup_type_die (TYPE_CONTEXT (type));
need_pop = 1;
}
+ else if (TYPE_CONTEXT (type) != NULL_TREE
+ && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
+ {
+ /* If this type is local to a function that hasn't been written
+ out yet, use a NULL context for now; it will be fixed up in
+ decls_for_scope. */
+ context_die = lookup_decl_die (TYPE_CONTEXT (type));
+ need_pop = 0;
+ }
else
{
context_die = declare_in_namespace (type, context_die);
break;
case NAMESPACE_DECL:
- dwarf2out_decl (decl);
+ if (dwarf_version >= 3 || !dwarf_strict)
+ dwarf2out_decl (decl);
+ else
+ /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace. */
+ decl_die = comp_unit_die;
break;
default:
/* Output any DIEs that are needed to specify the type of this data
object. */
- if ((TREE_CODE (decl_or_origin) == RESULT_DECL
- || TREE_CODE (decl_or_origin) == VAR_DECL)
- && DECL_BY_REFERENCE (decl_or_origin))
+ if (decl_by_reference_p (decl_or_origin))
gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
else
gen_type_die (TREE_TYPE (decl_or_origin), context_die);
if (!origin)
origin = decl_ultimate_origin (decl);
if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
- gen_formal_parameter_die (decl, origin, context_die);
+ gen_formal_parameter_die (decl, origin,
+ true /* Emit name attribute. */,
+ context_die);
else
gen_variable_die (decl, origin, context_die);
break;
gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
else
gen_type_die (TREE_TYPE (decl_or_origin), context_die);
- gen_formal_parameter_die (decl, origin, context_die);
+ gen_formal_parameter_die (decl, origin,
+ true /* Emit name attribute. */,
+ context_die);
break;
case NAMESPACE_DECL:
case IMPORTED_DECL:
- gen_namespace_die (decl, context_die);
+ if (dwarf_version >= 3 || !dwarf_strict)
+ gen_namespace_die (decl, context_die);
break;
default:
}
if (TREE_CODE (decl) == NAMESPACE_DECL)
- imported_die = new_die (DW_TAG_imported_module,
- lexical_block_die,
- lexical_block);
+ {
+ if (dwarf_version >= 3 || !dwarf_strict)
+ imported_die = new_die (DW_TAG_imported_module,
+ lexical_block_die,
+ lexical_block);
+ else
+ return;
+ }
else
imported_die = new_die (DW_TAG_imported_declaration,
lexical_block_die,
&& TYPE_P (context)
&& !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
return;
+
+ if (!(dwarf_version >= 3 || !dwarf_strict))
+ return;
+
scope_die = get_context_die (context);
if (child)
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
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;
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);
}
/* 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);
} 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. */
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)
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));
/* We can only use the low/high_pc attributes if all of the code was
in .text. */
- if (!have_multiple_function_sections)
+ if (!have_multiple_function_sections
+ || !(dwarf_version >= 3 || !dwarf_strict))
{
add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);