From patchwork Thu Aug 12 08:05:22 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 61537 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id D630DB70DD for ; Thu, 12 Aug 2010 18:05:42 +1000 (EST) Received: (qmail 6009 invoked by alias); 12 Aug 2010 08:05:39 -0000 Received: (qmail 5753 invoked by uid 22791); 12 Aug 2010 08:05:35 -0000 X-SWARE-Spam-Status: No, hits=-6.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 12 Aug 2010 08:05:24 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o7C85NBN005101 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 12 Aug 2010 04:05:23 -0400 Received: from tyan-ft48-01.lab.bos.redhat.com (tyan-ft48-01.lab.bos.redhat.com [10.16.42.4]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o7C85MJj013350 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 12 Aug 2010 04:05:22 -0400 Received: from tyan-ft48-01.lab.bos.redhat.com (tyan-ft48-01.lab.bos.redhat.com [127.0.0.1]) by tyan-ft48-01.lab.bos.redhat.com (8.14.4/8.14.4) with ESMTP id o7C85Ngf026623; Thu, 12 Aug 2010 10:05:23 +0200 Received: (from jakub@localhost) by tyan-ft48-01.lab.bos.redhat.com (8.14.4/8.14.4/Submit) id o7C85Mtx026622; Thu, 12 Aug 2010 10:05:22 +0200 Date: Thu, 12 Aug 2010 10:05:22 +0200 From: Jakub Jelinek To: Jason Merrill , Richard Henderson Cc: gcc-patches@gcc.gnu.org, Roland McGrath Subject: [PATCH] DW_OP_GNU_implicit_pointer support Message-ID: <20100812080522.GL702@tyan-ft48-01.lab.bos.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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 * 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 * 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; } --- gcc/cfgexpand.c +++ gcc/cfgexpand.c @@ -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)); --- gcc/cselib.c +++ gcc/cselib.c @@ -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; --- gcc/dwarf2out.c.jj 2010-08-11 10:47:28.083229922 +0200 +++ gcc/dwarf2out.c 2010-08-12 00:54:17.102190031 +0200 @@ -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_"; @@ -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)) { --- gcc/print-rtl.c +++ gcc/print-rtl.c @@ -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; --- gcc/rtl.c +++ gcc/rtl.c @@ -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; } --- gcc/rtl.def +++ gcc/rtl.def @@ -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 --- gcc/rtl.h +++ gcc/rtl.h @@ -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. */ --- include/dwarf2.h +++ include/dwarf2.h @@ -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,