@@ -2904,7 +2904,32 @@ expand_debug_expr (tree exp)
case ADDR_EXPR:
op0 = expand_debug_expr (TREE_OPERAND (exp, 0));
if (!op0 || !MEM_P (op0))
- return NULL;
+ {
+ if ((TREE_CODE (TREE_OPERAND (exp, 0)) == VAR_DECL
+ || TREE_CODE (TREE_OPERAND (exp, 0)) == PARM_DECL
+ || TREE_CODE (TREE_OPERAND (exp, 0)) == RESULT_DECL)
+ && !TREE_ADDRESSABLE (TREE_OPERAND (exp, 0)))
+ return gen_rtx_DEBUG_IMPLICIT_PTR (mode, TREE_OPERAND (exp, 0));
+
+ if (handled_component_p (TREE_OPERAND (exp, 0)))
+ {
+ HOST_WIDE_INT bitoffset, bitsize, maxsize;
+ tree decl
+ = get_ref_base_and_extent (TREE_OPERAND (exp, 0),
+ &bitoffset, &bitsize, &maxsize);
+ if ((TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL)
+ && !TREE_ADDRESSABLE (decl)
+ && (bitoffset % BITS_PER_UNIT) == 0
+ && bitsize > 0
+ && bitsize == maxsize)
+ return plus_constant (gen_rtx_DEBUG_IMPLICIT_PTR (mode, decl),
+ bitoffset / BITS_PER_UNIT);
+ }
+
+ return NULL;
+ }
op0 = convert_debug_memory_address (mode, XEXP (op0, 0));
@@ -700,6 +700,10 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
case DEBUG_EXPR:
return 0;
+ case DEBUG_IMPLICIT_PTR:
+ return DEBUG_IMPLICIT_PTR_DECL (x)
+ == DEBUG_IMPLICIT_PTR_DECL (y);
+
case LABEL_REF:
return XEXP (x, 0) == XEXP (y, 0);
@@ -834,6 +838,11 @@ cselib_hash_rtx (rtx x, int create)
+ DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x));
return hash ? hash : (unsigned int) DEBUG_EXPR;
+ case DEBUG_IMPLICIT_PTR:
+ hash += ((unsigned) DEBUG_IMPLICIT_PTR << 7)
+ + DECL_UID (DEBUG_IMPLICIT_PTR_DECL (x));
+ return hash ? hash : (unsigned int) DEBUG_IMPLICIT_PTR;
+
case CONST_INT:
hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
return hash ? hash : (unsigned int) CONST_INT;
@@ -4295,6 +4295,7 @@ enum dw_val_class
dw_val_class_macptr,
dw_val_class_file,
dw_val_class_data8,
+ dw_val_class_decl_ref,
dw_val_class_vms_delta
};
@@ -4333,6 +4334,7 @@ typedef struct GTY(()) dw_val_struct {
unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
+ tree GTY ((tag ("dw_val_class_decl_ref"))) val_decl_ref;
struct dw_val_vms_delta_union
{
char * lbl1;
@@ -4696,6 +4698,8 @@ dwarf_stack_op_name (unsigned int op)
return "DW_OP_GNU_uninit";
case DW_OP_GNU_encoded_addr:
return "DW_OP_GNU_encoded_addr";
+ case DW_OP_GNU_implicit_pointer:
+ return "DW_OP_GNU_implicit_pointer";
default:
return "OP_<unknown>";
@@ -4799,6 +4803,9 @@ loc_list_plus_const (dw_loc_list_ref lis
loc_descr_plus_const (&d->expr, offset);
}
+#define DWARF_REF_SIZE \
+ (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
+
/* Return the size of a location descriptor. */
static unsigned long
@@ -4905,12 +4912,15 @@ size_of_loc_descr (dw_loc_descr_ref loc)
size += 4;
break;
case DW_OP_call_ref:
- size += DWARF2_ADDR_SIZE;
+ size += DWARF_REF_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;
+ case DW_OP_GNU_implicit_pointer:
+ size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
+ break;
default:
break;
}
@@ -4947,6 +4957,7 @@ size_of_locs (dw_loc_descr_ref loc)
}
static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+static void get_ref_die_offset_label (char *, dw_die_ref);
/* Output location description stack opcode's operands (if any). */
@@ -5166,6 +5177,17 @@ output_loc_operands (dw_loc_descr_ref lo
}
break;
+ case DW_OP_GNU_implicit_pointer:
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES
+ + HOST_BITS_PER_WIDE_INT / 2 + 2];
+ gcc_assert (val1->val_class == dw_val_class_die_ref);
+ get_ref_die_offset_label (label, val1->v.val_die_ref.die);
+ dw2_asm_output_offset (DWARF_REF_SIZE, label, debug_info_section, NULL);
+ dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
+ }
+ break;
+
default:
/* Other codes have no operands. */
break;
@@ -5304,6 +5326,10 @@ output_loc_operands_raw (dw_loc_descr_re
dw2_asm_output_data_sleb128_raw (val2->v.val_int);
break;
+ case DW_OP_GNU_implicit_pointer:
+ gcc_unreachable ();
+ break;
+
default:
/* Other codes have no operands. */
break;
@@ -6518,6 +6544,15 @@ is_tagged_type (const_tree type)
|| code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
}
+/* Set label to debug_info_section_label + die_offset of a DIE reference. */
+
+static void
+get_ref_die_offset_label (char *label, dw_die_ref ref)
+{
+ sprintf (label, "%s+" HOST_WIDE_INT_PRINT_DEC,
+ debug_info_section_label, ref->die_offset);
+}
+
/* Convert a DIE tag into its string name. */
static const char *
@@ -13655,6 +13690,7 @@ mem_loc_descriptor (rtx rtl, enum machin
case CONCAT:
case CONCATN:
case VAR_LOCATION:
+ case DEBUG_IMPLICIT_PTR:
expansion_failed (NULL_TREE, rtl,
"CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
return 0;
@@ -14244,6 +14280,35 @@ concatn_loc_descriptor (rtx concatn, enu
return cc_loc_result;
}
+/* Helper function for loc_descriptor. Return DW_OP_GNU_implicit_pointer
+ for DEBUG_IMPLICIT_PTR RTL. */
+
+static dw_loc_descr_ref
+implicit_ptr_descriptor (rtx rtl, HOST_WIDE_INT offset)
+{
+ dw_loc_descr_ref ret;
+ dw_die_ref ref;
+
+ gcc_assert (TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == VAR_DECL
+ || TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == PARM_DECL
+ || TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == RESULT_DECL);
+ ref = lookup_decl_die (DEBUG_IMPLICIT_PTR_DECL (rtl));
+ ret = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
+ ret->dw_loc_oprnd2.val_class = dw_val_class_const;
+ if (ref)
+ {
+ ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+ ret->dw_loc_oprnd1.v.val_die_ref.die = ref;
+ ret->dw_loc_oprnd1.v.val_die_ref.external = 0;
+ }
+ else
+ {
+ ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
+ ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_IMPLICIT_PTR_DECL (rtl);
+ }
+ return ret;
+}
+
/* Output a proper Dwarf location descriptor for a variable or parameter
which is either allocated in a register or in a memory location. For a
register, we just generate an OP_REG and the register number. For a
@@ -14461,6 +14526,19 @@ loc_descriptor (rtx rtl, enum machine_mo
}
break;
+ case DEBUG_IMPLICIT_PTR:
+ loc_result = implicit_ptr_descriptor (rtl, 0);
+ break;
+
+ case PLUS:
+ if (GET_CODE (XEXP (rtl, 0)) == DEBUG_IMPLICIT_PTR
+ && CONST_INT_P (XEXP (rtl, 1)))
+ {
+ loc_result
+ = implicit_ptr_descriptor (XEXP (rtl, 0), INTVAL (XEXP (rtl, 1)));
+ break;
+ }
+ /* FALLTHRU */
default:
if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode
&& GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
@@ -19210,7 +19288,7 @@ gen_variable_die (tree decl, tree origin
if (declaration)
add_AT_flag (var_die, DW_AT_declaration, 1);
- if (decl && (DECL_ABSTRACT (decl) || declaration))
+ if (decl && (DECL_ABSTRACT (decl) || declaration || old_die == NULL))
equate_decl_number_to_die (decl, var_die);
if (! declaration
@@ -22172,6 +22250,17 @@ resolve_addr_in_expr (dw_loc_descr_ref l
&& loc->dw_loc_oprnd2.val_class == dw_val_class_addr
&& resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)))
return false;
+ else if (loc->dw_loc_opc == DW_OP_GNU_implicit_pointer
+ && loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
+ {
+ dw_die_ref ref
+ = lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
+ if (ref == NULL)
+ return false;
+ loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+ loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
+ loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
+ }
return true;
}
@@ -22451,17 +22540,6 @@ dwarf2out_finish (const char *filename)
add_ranges (NULL);
}
- /* Output location list section if necessary. */
- if (have_location_lists)
- {
- /* Output the location lists info. */
- switch_to_section (debug_loc_section);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
- DEBUG_LOC_SECTION_LABEL, 0);
- ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
- output_location_lists (die);
- }
-
if (debug_info_level >= DINFO_LEVEL_NORMAL)
add_AT_lineptr (comp_unit_die, DW_AT_stmt_list,
debug_line_section_label);
@@ -22503,6 +22581,17 @@ dwarf2out_finish (const char *filename)
switch_to_section (debug_abbrev_section);
output_abbrev_section ();
+ /* Output location list section if necessary. */
+ if (have_location_lists)
+ {
+ /* Output the location lists info. */
+ switch_to_section (debug_loc_section);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
+ DEBUG_LOC_SECTION_LABEL, 0);
+ ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+ output_location_lists (die);
+ }
+
/* Output public names table if necessary. */
if (!VEC_empty (pubname_entry, pubname_table))
{
@@ -529,7 +529,10 @@ print_rtx (const_rtx in_rtx)
case 't':
#ifndef GENERATOR_FILE
- dump_addr (outfile, " ", XTREE (in_rtx, i));
+ if (i == 0 && GET_CODE (in_rtx) == DEBUG_IMPLICIT_PTR)
+ print_mem_expr (outfile, DEBUG_IMPLICIT_PTR_DECL (in_rtx));
+ else
+ dump_addr (outfile, " ", XTREE (in_rtx, i));
#endif
break;
@@ -407,6 +407,10 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
case CONST_FIXED:
return 0;
+ case DEBUG_IMPLICIT_PTR:
+ return DEBUG_IMPLICIT_PTR_DECL (x)
+ == DEBUG_IMPLICIT_PTR_DECL (y);
+
default:
break;
}
@@ -527,6 +531,10 @@ rtx_equal_p (const_rtx x, const_rtx y)
case CONST_FIXED:
return 0;
+ case DEBUG_IMPLICIT_PTR:
+ return DEBUG_IMPLICIT_PTR_DECL (x)
+ == DEBUG_IMPLICIT_PTR_DECL (y);
+
default:
break;
}
@@ -711,6 +711,10 @@ DEF_RTL_EXPR(US_TRUNCATE, "us_truncate", "e", RTX_UNARY)
initialization status of variables. */
DEF_RTL_EXPR(VAR_LOCATION, "var_location", "tei", RTX_EXTRA)
+/* Used in VAR_LOCATION for a pointer to a decl that is no longer
+ addressable. */
+DEF_RTL_EXPR(DEBUG_IMPLICIT_PTR, "debug_implicit_ptr", "t", RTX_OBJ)
+
/* All expressions from this point forward appear only in machine
descriptions. */
#ifdef GENERATOR_FILE
@@ -931,6 +931,9 @@ extern const char * const reg_note_name[];
/* DEBUG_EXPR_DECL corresponding to a DEBUG_EXPR RTX. */
#define DEBUG_EXPR_TREE_DECL(RTX) XCTREE (RTX, 0, DEBUG_EXPR)
+/* VAR_DECL/PARM_DECL DEBUG_IMPLICIT_PTR takes address of. */
+#define DEBUG_IMPLICIT_PTR_DECL(RTX) XCTREE (RTX, 0, DEBUG_IMPLICIT_PTR)
+
/* Possible initialization status of a variable. When requested
by the user, this information is tracked and recorded in the DWARF
debug information, along with the variable's location. */
@@ -622,6 +622,7 @@ enum dwarf_location_atom
/* The following is for marking variables that are uninitialized. */
DW_OP_GNU_uninit = 0xf0,
DW_OP_GNU_encoded_addr = 0xf1,
+ DW_OP_GNU_implicit_pointer = 0xf2,
/* HP extensions. */
DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */
DW_OP_HP_is_value = 0xe1,
Hi! This patch implements the GCC side of implicit pointer DWARF extension, which allows optimized out pointers to be partially usable in debug info consumers. For details see the proposal Roland sent last night to Dwarf-Discuss mailing list. In short, the user can dereference such pointers in the debugger, even when what they are pointing to doesn't live in memory (can live in registers, or have constant values, or piecewise mix thereof), can query their type (that was possible before already), but can't print their value. In cc1plus .debug_info/.debug_loc this DW_OP_GNU_implicit_pointer op is used over 22000 times. Ok for trunk (assuming nobody suggests some encoding change on Dwarf-Discuss within a few days - as DWARF 5 is probably years away, we want to implement this as a GNU vendor extension and if it is accepted for DWARF 5, switch over to the standard op when DWARF 5 is drafted or released, but if possible we'd like to just switch to a different op code instead of switching semantics as well)? Jakub 2010-08-12 Jakub Jelinek <jakub@redhat.com> * rtl.def (DEBUG_IMPLICIT_PTR): New rtl code. * rtl.h (DEBUG_IMPLICIT_PTR_DECL): Define. * rtl.c (rtx_equal_p_cb, rtx_equal_p): Handle DEBUG_IMPLICIT_PTR. * print-rtl.c (print_rtx): Likewise. * cselib.c (rtx_equal_for_cselib_p, cselib_hash_rtx): Likewise. * cfgexpand.c (expand_debug_expr): Generate DEBUG_IMPLICIT_PTR for ADDR_EXPR with non-addressable object. * dwarf2out.c (enum dw_val_class): Add dw_val_class_decl_ref. (struct dw_val_struct): Add v.val_decl_ref. (dwarf_stack_op_name, output_loc_operands, output_loc_operands_raw): Handle DW_OP_GNU_implicit_pointer. (size_of_loc_descr): Likewise. Fix up DW_OP_call_ref size. (get_ref_die_offset_label): New function. (implicit_ptr_descriptor): New function. (mem_loc_descriptor): Handle DEBUG_IMPLICIT_PTR. (loc_descriptor): Likewise. (gen_variable_die): Put even definitions into decl_die_table. (resolve_addr_in_expr): Resolve still unresolved DW_OP_GNU_implicit_pointer operands, if it can't be resolved return false. (dwarf2out_finish): Call output_location_lists after outputting .debug_info and .debug_abbrev instead of before. * dwarf2.h (DW_OP_GNU_implicit_pointer): New. 2010-08-12 Roland McGrath <roland@redhat.com> * dwarf2out.c (DWARF_REF_SIZE): Define. (size_of_loc_descr): Use it for DW_OP_call_ref. struct S { int *x, y; }; int u[6]; static inline void add (struct S *a, struct S *b, int c) { *a->x += *b->x; a->y += b->y; u[c + 0]++; a = (struct S *) 0; u[c + 1]++; a = b; u[c + 2]++; } int foo (int i) { int j = i; struct S p[2] = { {&i, i * 2}, {&j, j * 2} }; add (&p[0], &p[1], 0); p[0].x = &j; p[1].x = &i; add (&p[0], &p[1], 3); return i + j; } int bar (int i) { int *j = &i; int **k = &j; int ***l = &k; i++; return i; }